PDA

View Full Version : Calling an object's method from a C-style function




TurboLag
Apr 10, 2008, 02:02 PM
I am trying to access some instance variables from a C function in the same source file. Declaring the instance variables as public does not make them visible, so the only alternative is to declare them outside the @interface, thus making them global. I am sure this is not the proper approach.

Also, how can I call a method from within the C function if the object itself is not visible?

Thanks.



kainjow
Apr 10, 2008, 03:37 PM
C functions work the same in Objective-C as they do in C++. They can't access instance variables or methods. You need to pass in a reference of your class to the function and then you can do whatever you want. For example:

void myNiftyFunc(SomeObject *obj) {
id ivar = [obj ivar];
}


@implementation SomeObject

- (void)blah {
myNiftyFunc(self);
}

- (id)ivar {
return someIvar;
}

@end

TurboLag
Apr 10, 2008, 04:00 PM
The problem is that the C function is a callback routine, and I cant change how it is called. So I am stuck with the parameters it is defined with:

void callback (void * target, unsigned long result, void * refcon, void * sender);

The setup for the callback is:

HIDresult = HIDSetQueueCallback (pFoundDevice, (IOHIDCallbackFunction)callback);

I could try wrapping the function as a ObjC method, such as:
- (void)callback: (void *) target Result:(unsigned long) result Refcon:(void *) refcon Sender:(void *) sender;

but I can't figure the proper syntax for the HIDSetQueueCallback function call. Any advice?

kainjow
Apr 10, 2008, 04:13 PM
Usually with a callback function you can setup it up to pass in a pointer, and for Objective-C you would pass in self, but for what you're doing I don't think it's possible since HIDSetQueueCallback() only takes two arguments.

Edit: looks like you're using some code from Apple's examples. They end up just calling setEventCallout() which sets up your callback. Looks like it could be changed to work around the issue but it'd probably be easier to use a global variable (ugly though).

lee1210
Apr 10, 2008, 04:25 PM
I feel somewhat dirty suggesting this, but it may work:

Have a global pointer defined in a file that points to the type of the object that has the member you need access to. In this file, define 2 functions:

objecttype *globalobj;

registerObject(objecttype *myobj) {
globalobj = myobj;
}

id getIvar() {
return [globalobj ivar];
}

Before any of the "worker" code, call registerObject passing the instance of your object where you have it available, or registerObject(self) from a method in your object instance.

Then in your callback function, you can call getIvar. This isn't really any better than having a global variable with the value in it, but it at least keeps you from having to keep that value "synchronized" with the objects member.

-Lee

Krevnik
Apr 10, 2008, 05:32 PM
Since everyone else is throwing in information, I'll throw in my two cents: refcons are your friend in this case.

When you setup the callback, you want to also search around for how to set the refcon on the callback. The poster a couple posts above me has the same idea. You set the refcon to the Obj-C object you need to call into from the callback, and then from the C method, you can typecast refcon into the Obj-C object and call into it.

EDIT: I randomly stumbled on this post on the Apple dev lists which includes an updated HIDSetQueueCallback which will let you pass in a refcon pointer. Use it wisely. :)

http://lists.apple.com/archives/mac-games-dev/2002/Nov/msg00018.html

TurboLag
Apr 11, 2008, 11:25 AM
Thanks Krevnik.

Works like a charm. I pass the setup function a pointer to my object, then typecast it in the callback. Much cleaner approach.

Now to remove those global variables . . .