views:

652

answers:

1

Hey guys,

I'm writing a wrapper around a C library in Objective-C. The library allows me to register callback functions when certain events occur.

The register_callback_handler() function takes a function pointer as one of the parameters.

My question to you gurus of programming is this: How can I represent an Objective-C method call / selector as a function pointer?

  • Would NSInvocation be something useful in this situation or too high level?
  • Would I be better off just writing a C function that has the method call written inside it, and then pass the pointer to that function?

Any help would be great, thanks.

+2  A: 

Does register_callback_handler() also take a (void*) context argument? Most callback APIs do.

If it does, then you could use NSInvocation quite easily. Or you could allocate a little struct that contains a reference to the object and selector and then cobble up your own call.

If it only takes a function pointer, then you are potentially hosed. You need something somewhere that uniquely identifies the context, even for pure C coding.

Given that your callback handler does have a context pointer, you are all set:

typedef struct {
    id target;
    SEL selector;
    // you could put more stuff here if you wanted
    id someContextualSensitiveThing;
} TrampolineData;

void trampoline(void *freedata) {
    TrampolineData *trampData = freedata;
    [trampData->target performSelector: trampData->selector withObject: trampData-> someContextualSensitiveThing];
}

...
TrampolineData *td = malloc(sizeof(TrampolineData));
... fill in the struct here ...
register_callback_handler(..., trampoline, td);

That is the general idea, anyway. If you need to deal with non-object typed arguments and/or callbacks, it gets a little bit trickier, but not that much. The easiest way is to call objc_msgSend() directly after typecasting it to a function pointer of the right type so the compiler generates the right call site (keeping in mind that you might need to use objc_msgSend_stret() for structure return types).

bbum
I can't divulge too much info about the library, I'm not permitted :(. The parameters are (XFINST inst, unsigned int pid, void *func, void *freedata); The first is the client instancem, the second is a packet ID for the particular event, the third is the callback function pointer, and the last is a pointer to some data that you may want passed to the call back function.
Jasarien
Well, there ya go... you are golden, then.
bbum
You mean I can use NSInvocation?
Jasarien
No need. See above.
bbum
@Jasarien, be mindful that `void *func` (as given in your comment) is a `pointer to object-type`, and not a `pointer to function-type`. The standard is silent on whether or not converting/casting between the two types is legal, and thus is implicitly undefined behavior. This is probably not a problem for the 'market leader' objc targets, but something to keep in mind if you're shooting for maximum portability. Good practice to move it to a proper function-type argument anyways.
johne
oh, as a point of clarification on my above comment- `pointer to object-type` is the C standard definition for 'object-type' (i.e., the pointer you get from `malloc()`), not an Objective-C object.
johne