swiftstringmigrationc-stringsswift6

How to convert cString into String in Swift6?


The following code produces a warning in Swift6:

'init(cString:)' is deprecated: Use String(decoding: array, as: UTF8.self) instead, after truncating the null termination.

  var size = 0
  sysctlbyname("hw.model", nil, &size, nil, 0)
  
  var modelIdentifier: [CChar] = Array(repeating: 0, count: size)
  sysctlbyname("hw.model", &modelIdentifier, &size, nil, 0)
  
  return String(cString: modelIdentifier)

Writing:

  return String(decoding: modelIdentifier, as: UTF8.self)

produces an error:

Type of expression is ambiguous without a type annotation

How do I get rid of this ?


Solution

  • Writing:

    return String(decoding: modelIdentifier, as: UTF8.self)
    

    produces an error:

    Type of expression is ambiguous without a type annotation
    

    Unfortunately, this is because the type of String(decoding:as:) is

    init<C, Encoding>(
        decoding codeUnits: C,
        as sourceEncoding: Encoding.Type
    ) where C : Collection, Encoding : _UnicodeEncoding, C.Element == Encoding.CodeUnit
    

    i.e., codeUnits needs to be a collection of UTF8.CodeUnit, and UTF8.CodeUnit is UInt8, not CChar.

    Instead, you can use String(utf8String:), which takes a [CChar] directly:

    var modelIdentifier: [CChar] = Array(repeating: 0, count: size)
    sysctlbyname("hw.model", &modelIdentifier, &size, nil, 0)
    
    guard let identifier = String(utf8String: modelIdentifier) else {
        // Handle this in some appropriate fashion
        fatalError("Invalid model identifier")
    }
    
    return identifier