Using a C API function in Swift 3 that has a callback function pointer as an argument

c, callback, macos, swift

Solution

Passing a global function as callback should work, but the last parameter must be an optional `UnsafeMutableRawPointer?`:

func callbackCalled(handle: HSYNC, channel: DWORD, data: DWORD, user: UnsafeMutableRawPointer?) -> Void {
    print("callback called")
}

Syncer(h, c, d, callbackCalled, u)

Alternatively, pass a closure expression (and let compiler infer the types of the parameters):

Syncer(h, d, c, {
    (handle, channel, data, user) in
    // ...
}, u)

You can not pass an instance method as a callback, compare How to use instance method as callback for function which takes only func or literal closure.

If `NULL` is not a valid value for the user parameter then you can add "Nullability annotations" to the C declaration, e.g.

typedef void (CALLBACK SYNCPROC)(HSYNC h, DWORD c, DWORD d, void * _Nonnull user);

and then it will be represented as a non-optional `UnsafeMutableRawPointer` in Swift.

Problem

I'm building a wrapper/interface for a C library with Swift 3. One of the functions that I need to call require a function pointer for callback as an argument. In detail: after said function has successfully done the file operation it has to, it then calls the function the given argument pointer refers to - essentially letting me do other operations with said data The function looks like this: `HSYNC MXDEF (Syncer)(DWORD h, DWORD t, QWORD p, SYNCPROC *proc, void *user);` The callback function type `SYNCPROC` is defined as follows: `typedef void (CALLBACK SYNCPROC)(HSYNC h, DWORD c, DWORD d, void *user);` I have only been able to use the `Syncer` function with setting the callback argument to nil so far. I tried creating a function outside the Class as someone suggested: `func callbackCalled(handle: HSYNC, channel: DWORD, data: DWORD, user: UnsafeMutableRawPointer) -> Void { print("callback called") }` And I even tried this method within the Class: `var callbackTest : @convention(c) (_ handle: HSYNC, _ channel: DWORD, _ data: DWORD, _ user: UnsafeMutableRawPointer) -> Void = { print("\($0) \($1) \($2) \($3)") }` But however I tried / read upon this topic I always end up with this error message: `Cannot convert value of type 'Void' (aka '()') to expected argument type '(@convention(c) (HSYNC, DWORD, DWORD, UnsafeMutableRawPointer?) -> Void)!'` My question is: How am I supposed to satisfy the criteria regarding this type of a callback function? I haven't been able to find any info regarding these types of callback functions, presumably due to my lack of knowledge and thorough understanding of the problem. Thank you in advance!

Original source

Related problems