In Swift 2, the C function
size_t embeddedSize ( const char *_Nullable string );
displayed in Swift as
func embeddedSize(string: UnsafePointer<Int8>) -> Int
and you can pass the (optional) Swift string as an argument, as described in Interacting with the API API in "Using Swift with Cocoa and Objective-C":
Constant pointers
When a function is declared as taking an UnsafePointer<Type> argument, it can accept any of the following:
- ...
- The value is A
String if Type is Int8 or UInt8 . The string will be automatically converted to UTF8 in the buffer, and a pointer to this buffer will be passed to the function. - ...
You can also pass nil because in Swift 2, nil is a valid value for UnsafePointer .
As @zneak noted, "automatic conversion" in UTF-8 does not work for extra lines in Swift 2, so you should (conditionally) expand the line:
let someString: String? = "Some String" let s2: size_t if let str = someString { s2 = embeddedSize(str) } else { s2 = embeddedSize(nil) }
Using the map Optional method and the nil-coalescing operator ?? , it can be written more compactly, since
let someString: String? = "Some String" let s2 = someString.map { embeddedSize($0) } ?? embeddedSize(nil)
One common solution was proposed by @zneak .
Here is another possible solution. String has a method
func withCString<Result>(@noescape f: UnsafePointer<Int8> throws -> Result) rethrows -> Result
which causes a closure by a pointer to a UTF-8 string representation, the lifetime is through f . So for an optional string, the following two statements: are equivalent:
let s1 = embeddedSize("Test") let s1 = "Test".withCString { embeddedSize($0) }
We can define a similar method for optional strings. since extensions of generic types can restrict only the placeholder type to protocols, and not to specific types, we must define the protocol that String matches:
protocol CStringConvertible { func withCString<Result>(@noescape f: UnsafePointer<Int8> throws -> Result) rethrows -> Result } extension String: CStringConvertible { } extension Optional where Wrapped: CStringConvertible { func withOptionalCString<Result>(@noescape f: UnsafePointer<Int8> -> Result) -> Result { if let string = self { return string.withCString(f) } else { return f(nil) } } }
Now the above C function can be called with an extra string argument
let someString: String? = "Some String" let s2 = someString.withOptionalCString { embeddedSize($0) }
For multiple arguments of a C string, a close can be nested:
let string1: String? = "Hello" let string2: String? = "World" let result = string1.withOptionalCString { s1 in string2.withOptionalCString { s2 in calculateTotalLength(s1, s2) } }
Apparently, the problem is solved in Swift 3. Here the C-function is mapped to
func embeddedSize(_ string: UnsafePointer<Int8>?) -> Int
and passing String? compiles and works as expected, for both nil and non nil .