简体   繁体   中英

ivars when mixing C and Objective-C

I'm writing an Objective-C wrapper for a C library and having problems accessing the references of my ivars.

The C library requires that I specify a function pointer that handles events, I specify it during the initialization of my Objective-C class.

- (id) init {
    [super init];
    RegisterClient(&handleEvent);
    return self;
}

The C library is able to start searching for something and will then call the handleEvent function in case anything happened during the search. The function (basically) looks like this.

int handleEvent(void *Event) {
    [delegate didFinishSearching];
    return 0;
}

At least I'd wish it looked like this. The problem is that the code won't build because 'delegate' undeclared (first use in function) (of course I have declared it, I can call [delegate didFinishSearching] from any Objective-C method but not from a C function). Older questions from stackoverflow suggest to define an additional variable (eg theDelegate ) in the header file:

id theDelegate;

@interface Controller : NSObject {
    id delegate;
}
@property (assign) id delegate;
@end

Then, whenever I change the value of delegate to a new one, I have to assign this value to theDelegate , too.

Since my C is somewhat rusty, here are my questions:

1) Can I pass the RegisterClient C function a pointer to an Objective-C method instead of a pointer to a function as an argument in order to avoid the C function handleEvent completely?

2) If not: When I create multiple instances of this Objective-C class, will theDelegate be the same for all instances? (After all, it's not declared as an instance variable...)

Objective-C methods are C functions, but they have two hidden parameters at the front, so they won't have the int f(void *) signature.

What you probably want to do is use an libffi closure. That allows you to create a function with exactly the signature that you want, but that also has a pointer to your object passed along with it. See the example in the ffi_prep_closure man page . Your handleEvent function would probably then change to look something like this:

static void handleEventClosure(ffi_cif * cif, void * result, void ** args, void * userdata)
{
    // Arguments.
    void * Event = *args[0];

    // Closed-over data.
    id delegate = (id)userdata;

    // Execute the method.
    [delegate didFinishSearching];

    // Smaller than sizeof(long), so use ffi_arg or ffi_sarg (unsigned or signed).
    *(ffi_sarg *)result = (ffi_sarg)0;
}

Most of the time C Libraries like the one you describe accept a "userinfo" parameter conveniently size to match a pointer. You can use this to your advantage by passing your object as this "userinfo" parameter.

Then in callbacks, you cast the pointer back to an object and make the calls you need.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM