Context capturing C function pointers in Swift.

Take the following code:

func foo() {
    let bar = NSObject()

    let f: (@convention(c) () -> ()) = {
        print(bar)
    }
}

This will not compile. You will instead be presented with the following error:

error: a C function pointer cannot be formed from a closure that captures context

While you are unlikely to ever encounter this error in typical iOS development, it may arise as the result of, say, an attempt to interface with a low-level C library/framework. In my case, I was trying to construct a parameter for a low-level POSIX function (pthread_create), which only accepted a C function pointer.

There is a (dirty) workaround:

import ObjectiveC
import Swift

func cFunction(_ block: (@escaping @convention(block) () -> ()))
    -> (@convention(c) () -> ()) {
    return unsafeBitCast(
        imp_implementationWithBlock(block),
        to: (@convention(c) () -> ()).self
    )
}

This effectively allows you to write:

func foo() {
    let bar = NSObject()

    let f: (@convention(c) () -> ()) = cFunction {
        print(bar)
    }
}

Which is, in fact, valid Swift code.

So… what does cFunction do? It:

While this works, there are a few points to note:

 
47
Kudos
 
47
Kudos

Now read this

Losing My Touch

I’d hate to think that I’m losing my touch, With reality, with thoughts—it’s just too much. The dynamics, to me, are quite unclear Who, or what, am I supposed to be here? I hate these emotions that I suddenly feel I’m aware of it now, I’... Continue →