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:

 
18
Kudos
 
18
Kudos

Now read this

Songs of the Week #3

I’ve been putting off writing in favor of professional crastination, but no more! This is technically week 5 or 6, but “mah blog mah rulez” - I’m going to call it week 3. Boasty (feat. Idris Elba) by Wiley, Stefflon Don & Sean Paul #... Continue →