Charlesism Charlesism - 10 months ago 72
Swift Question

How to convert a CFunctionPointer to an EventHandlerUPP?

I have a C function called Foo_C_Func, which I need to use as a callback. The rest of the app is coded in Swift. As I understand it, the following code should work, but instead I get a compiler error.

// typealias makes our function signature easier to read

typealias Sig = ( EventHandlerCallRef, EventRef, UnsafeMutablePointer<Void>) -> OSStatus

// We need to make a CFunctionPointer to the C function

var ptr = UnsafeMutablePointer<Sig>.alloc(1)
ptr.initialize( Foo_C_Func )
let c_ptr = COpaquePointer( ptr )

let proc_ptr = CFunctionPointer<Sig>( c_ptr ) as EventHandlerProcPtr

// now we should be able to create the EventHandlerUPP

let handler_upp = NewEventHandlerUPP( proc_ptr )

Trying to Build this fails with the following error:

Undefined symbols for architecture x86_64:

"_Foo_C_Func", referenced from:

__TTOFSC10Foo_C_FuncFTVSs14COpaquePointerS_GVSs20UnsafeMutablePointerT___VSs5Int32 in Demo.o

"_NewEventHandlerUPP", referenced from:

__TFC17DemocfMS0_FT_S0_ in Demo.o

ld: symbol(s) not found for architecture x86_64

I also notice when I hover over the last line, that the Xcode tooltip shows the return type of NewEventHandlerUpp to be (EventHandlerProcPtr) rather than EventHandlerProcPtr.

Am I doing it wrong, or is it impossible to create an EventHandlerUPP within Swift?

Answer Source

Here's an alternate answer, if you're using Swift 3. Swift 3 is different than Swift 2, in that the latter sucks, whereas the former is usable.

let hotkey_callback: EventHandlerUPP = { _, _, _ in
    // Do stuff
    return noErr

var handler: EventHandlerRef? = nil

var spec = EventTypeSpec( 
    eventClass: OSType(kEventClassKeyboard), eventKind:  UInt32(kEventHotKeyPressed) 

let status = InstallEventHandler( 
    GetEventDispatcherTarget(), hotkey_callback, 1, &spec, nil, &handler 

Note that we can use "&" to avoid manually allocating pointers now, and note that adhering to the informal "EventHandlerUPP" protocol is now explicit and doesn't require our manually declaring the Type of each argument. So much easier to read now :)