I have ViewController in objective-c and most of my code is c++ (.mm). I'd like to setup some callbacks to member functions from obj-c (in c++) and call them from c++. Something like this (it's very simplifyed):
@interface MyClass
{ }
-(void)my_callback;
@end
@implementation MyClass
-(void)my_callback
{
printf("called!\n");
}
-(void)viewDidLoad
{
// setup_callback( "to my_callback ?" );
}
@end
and:
void setup_callback(void(*func)()) { func(); }
this is not correct of course. Any advice how can I do it, please?
Because C++ and Obj-C are both supersets of C, you can have your C++ code callback to a C function. To communicate the callback back to your Obj-C object, just make sure that the C callback arguments includes a pointer to the original Obj-C object.
You can freely mix Obj-C and C++ in your .mm files - it's referred to as "Objective-C++".
To keep isolation of your C++ code and Objective-C code, you could create a lightweight facade between them which would make Objective-C method calls (in the usual way) from within C++ callbacks.
I don't think that's possible: calling an Objective-C callback within C++ code. The other way around is possible.
What I did when I had this issue is to write an EVENT_LOOP running forever in Objective-C, and get the events from a C++
std::vector
instance. That way, in C++, if you want to "call" a callback in Objective-C, you just add the event to the correspondingstd::vector
.You have a few options.
Using blocks
You may use blocks to convey your callback work. This is probably the simplest solution as it allows you to call your code without having to pass any parameter to the callback "function". Blocks work in C and all its supersets with Clang, and Clang++ even allows implicit casts between blocks and lambdas.
That might require some reworking on the C++ end to accept functors (or just blocks if it's simpler) instead of function pointers.
Since blocks create closures, they're very convenient for that kind of works.
Blocks are an Apple extension to C, C++ and Objective-C. See more about them here.
Use the Objective-C runtime to acquire the function pointer to the method you want to call
Use the Objective-C runtime to access the function pointer of your selector. This is more tedious and requires you to keep track of three variables (the object to call the method on, the selector to use, and the method implementation), but it actually works even in the case you can't use the Objective-C syntax.
Objective-C method implementations are function pointers with this signature:
Where
self
is what you'd expect,_cmd
is the selector that caused this method call (the_cmd
variable is actually available in all Objective-C methods, try it), and the rest is considered variadic. You need to castIMP
variables into the proper function signature because the calling convention for variadic C functions doesn't always match the calling convention for Objective-C method calls (the Objective-C method call is the standard function calling convention for your compiler, probably eithercdecl
or the amd64 calling convention, and the variadic calling convention is not always the same). Areinterpret_cast
will be able to do it.Here's some code I put together for similar intents. It uses C++11 variadic templates to help with getting the proper function signature.
Also take care that your instance is not
nil
before using the function call, becausenil
checking is handled by the Objective-C runtime. In this case, we're bypassing it.Keep track of an object and a
SEL
Use
-[NSObject performSelector:]
to perform your callback. Basically a simpler version of the Objective-C runtime solution.Wrapping your call inside a C++ function
I think this one doesn't really need any example. Create a function that accepts your object type as the first parameter and call the method you want on it. Similarly to the
SEL
solution, you then need to separately keep track of the function to call and the object on which to call it.