I'm trying to compile some code on Linux that uses both CoreFoundation and Foundation, but Linux doesn't implement bridging in the same way macOS and iOS do.
Bridging between Objective-C and Swift works:
import Foundation
import CoreFoundation
import Glibc
func wantsNSString(_ string: NSString) {
print(string)
}
let string = "Hello, world!"
wantsNSString(string._bridgeToObjectiveC())
But I can't figure out how to bridge to CoreFoundation. I can't just pass an NSString
to a function that wants a CFString
:
import Foundation
import CoreFoundation
import Glibc
func wantsCFString(_ string: CFString) {
print(string)
}
let string = "Hello, world!"
wantsCFString(string._bridgeToObjectiveC()) //error: cannot convert value of type 'String._ObjectType' (aka 'NSString') to expected argument type 'CFString'
I can't just cast it like on macOS:
import Foundation
import CoreFoundation
import Glibc
func wantsCFString(_ string: CFString) {
print(string)
}
let string = "Hello, world!"
wantsCFString(string._bridgeToObjectiveC() as CFString)
//error: 'String._ObjectType' (aka 'NSString') is not convertible to 'CFString'; did you mean to use 'as!' to force downcast?
Using as!
like the error message suggests compiles but results in a crash at runtime (Illegal instruction
), and as?
produces the error:
error: conditional downcast to CoreFoundation type 'CFString' will always succeed
Bridging.swift
has protocols for converting between NS and CF types, and many types have initializers and properties, but those are all internal
or private
. I could just use CFStringCreateWithCString
, but this needs to work with other class pairs like InputStream
and CFReadStream
.
Am I missing something here, or is there really no way to convert between Foundation and CoreFoundation types on Linux?
It looks like I can unsafeBitCast
NSString
to/from CFString
:
import Foundation
import CoreFoundation
import Glibc
func wantsCFString(_ string: CFString) {
print(string)
}
let string = "Hello, world!"
wantsCFString(unsafeBitCast(string._bridgeToObjectiveC(), to: CFString.self)
//prints "Hello, world!"
This makes sense, since CoreFoundation and Foundation types were designed to have the same memory layout -- that's why toll-free bridging works. I'm somewhat surprised that it works with the Swift implementation of Foundation though.