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?
You have a few options.
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.
#include <dispatch/dispatch.h>
void setup_callback(dispatch_block_t block)
{
// required to copy the block to the heap, otherwise it's on the stack
dispatch_block_t copy = [block copy];
// setup stuff here
// when you want to call the callback, do as if it was a function pointer:
// block();
}
int main()
{
MyClass* instance = [[MyClass alloc] init];
setup_callback(^{
[instance callback_method];
});
}
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 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:
typedef void (*IMP)(id self, SEL _cmd, ...);
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 cast IMP
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 either cdecl
or the amd64 calling convention, and the variadic calling convention is not always the same). A reinterpret_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.
#include <objc/runtime.h>
template<typename TReturnType, typename... TArguments>
auto GetInstanceMethodPointer(Class class, SEL selector) -> TReturnType (*)(id, SEL, TArguments...)
{
Method m = class_getInstanceMethod(class, selector);
IMP imp = method_getImplementation(m);
return reinterpret_cast<TReturnType (*)(id, SEL, TArguments...)>(imp);
}
int main()
{
MyClass* instance = [[MyClass alloc] init];
auto foo = GetInstanceMethodPointer<void>(
[MyClass class],
@selector(my_callback));
// foo is a void (*)(id, SEL) function pointer
foo(instance, @selector(my_callback));
}
Also take care that your instance is not nil
before using the function call, because nil
checking is handled by the Objective-C runtime. In this case, we're bypassing it.
SEL
Use -[NSObject performSelector:]
to perform your callback. Basically a simpler version of the Objective-C runtime solution.
void setup_callback(id object, SEL selector)
{
// do stuff
// to execute the callback:
// [object performSelector:selector];
}
int main()
{
MyClass* instance = [[MyClass alloc] init];
setup_callback(instance, @selector(my_callback));
}
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.