How should this function pointer typedef be called in swift?

I'm struggling to grasp how to implement this imported C function in swift.

typedef void (*method_handler)(const msg_data_ptr msg, const char *types,
                                   arg_ptr *argv, int argc, void *user_data);
func handler(args)
{
    for (i, arg) in args.enumerated() {
        print("argument \(i) is: \(arg)")
    }
}

passed in here:

add_handler_new("handler", &handler, nil, 0, 1);

Cannot convert value of type '() -> ()' to expected argument type 'method_handler?' (aka 'Optional<@convention(c) (Optional<UnsafeMutablePointer<msg_data>>, Optional<UnsafePointer>, Optional<UnsafeMutablePointer<Optional<UnsafeMutablePointer>>>, Int32, Optional) -> ()>')

In my experience the easiest way to find the right signature is to let Xcode do the heavy lifting:

  1. Type add_handler_new into your Swift file.

  2. Trigger code completion.

  3. Accept the suggested completion.

  4. Tab across to the second parameter.

  5. Hit return to expand.

Xcode will then insert the correct outline for your method.

For example, if I have these C declarations:

struct msg_data;
typedef struct msg_data * msg_data_ptr;

struct arg;
typedef struct arg * arg_ptr;

typedef void (*method_handler)(const msg_data_ptr msg, const char *types,
                                   arg_ptr *argv, int argc, void *user_data);
extern void add_handler_new(const char * name, method_handler handler, void * somePtr, int someIntA, int someIntB);

I end up with this expansion:

add_handler_new("handler", { <#msg_data_ptr?#>, <#UnsafePointer<CChar>?#>, <#UnsafeMutablePointer<arg_ptr?>?#>, <#Int32#>, <#UnsafeMutableRawPointer?#> in
    <#code#>
}, nil, 0, 1)

Note that Xcode expands this to a closure. You could, in theory, take this signature and use it to declare a standalone function (handler() in your example) but things get complicated because that function has to be @convention(c). IMO it’s easiest to just write the standalone function as Swift and then call it from the closure.

func handler() {
    … code here …
}

add_handler_new("handler", { _, _, _, _, _ in
    handler()
}, nil, 0, 1)

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

2 Likes