3

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!

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the great and speedy help once again! I've messed up the syntax - now it works perfectly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.