Home > Net >  Is there a difference between String(validatingUTF8:) and String(utf8String:)?
Is there a difference between String(validatingUTF8:) and String(utf8String:)?

Time:12-25

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.

  • Related