Bridging to/from CoreFoundation on Linux
Asked Answered
N

1

8

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?

Newbill answered 3/10, 2016 at 18:58 Comment(2)
Does this work? https://mcmap.net/q/367558/-how-to-convert-a-swift-string-to-cfstring Ugly double cast. Don't know about Linux, though. The big "gotcha" with Swift on Linux is that the ObjC runtime isn't there.Ldopa
@JoshCaswell No; bridging between Swift and Foundation isn't done automatically by the compiler yet, which is why I have to use the temporary _bridgeToObjectiveC method, and I tried casting from NSString to CFString in my third example.Newbill
N
1

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.

Newbill answered 8/10, 2016 at 22:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.