Those two functions seem to have very close signatures and very close descriptions:
String.init(utf8String:)
Creates a string by copying the data from a given null-terminated C array of UTF8-encoded bytes.
String.init(validatingUTF8:)
Creates a new string by copying and validating the null-terminated UTF-8 data referenced by the given pointer.
Since both are nullable initializers, what are their actual differences? Is there a possible input that would give a different output for each? If they are identical in behavior, then which one is recommended to use?
CodePudding user response:
String.init(validatingUTF8:)
is a method from the Swift standard library, the implementation is in CString.swift:
public init?(validatingUTF8 cString: UnsafePointer<CChar>) {
let len = UTF8._nullCodeUnitOffset(in: cString)
guard let str = cString.withMemoryRebound(to: UInt8.self, capacity: len, {
String._tryFromUTF8(UnsafeBufferPointer(start: $0, count: len))
})
else { return nil }
self = str
}
String.init(utf8String:)
is implemented in NSStringAPI.swift:
/// Creates a string by copying the data from a given
/// C array of UTF8-encoded bytes.
public init?(utf8String bytes: UnsafePointer<CChar>) {
if let str = String(validatingUTF8: bytes) {
self = str
return
}
if let ns = NSString(utf8String: bytes) {
self = String._unconditionallyBridgeFromObjectiveC(ns)
} else {
return nil
}
}
and is the Swift overlay for the Foundation NSString
initializer
- (nullable instancetype)initWithUTF8String:(const char *)nullTerminatedCString
which in turn is implemented non-Apple platforms in swift-corelibs-foundation/Sources/Foundation/NSString.swift as
public convenience init?(utf8String nullTerminatedCString: UnsafePointer<Int8>) {
guard let str = String(validatingUTF8: nullTerminatedCString) else { return nil }
self.init(str)
}
So there is no difference in how the two methods convert C strings, but String.init(utf8String:)
needs import Foundation
whereas String.init(validatingUTF8:)
does not need additional imports.