Tiene algunas opciones.
utilizando bloques
Es posible utilizar bloques para transmitir su trabajo de devolución de llamada. Esta es probablemente la solución más simple, ya que le permite llamar a su código sin tener que pasar ningún parámetro a la "función" de devolución de llamada. Los bloques funcionan en C y todos sus superconjuntos con Clang, y Clang ++ incluso permite conversiones implícitas entre bloques y 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];
});
}
que podrían requerir alguna reelaboración en el extremo C++ para aceptar funtores (o sólo bloques si es más sencillo) en lugar de punteros de función.
Dado que los bloques crean cierres, son muy convenientes para ese tipo de trabajos.
Los bloques son una extensión de Apple para C, C++ y Objective-C. Ver más sobre ellos here.
Utilice el tiempo de ejecución de Objective-C para adquirir el puntero de función para el método al que desea llamar
Usar el tiempo de ejecución de Objective-C para acceder a la función de puntero de su selector. Esto es más tedioso y requiere que realice un seguimiento de tres variables (el objeto para invocar el método, el selector a usar y la implementación del método), pero en realidad funciona incluso en el caso de que no pueda usar el Objective-C sintaxis.
implementaciones de métodos de Objective-C son los punteros de función con esta firma:
typedef void (*IMP)(id self, SEL _cmd, ...);
Dónde self
es lo que se espera, _cmd
es el selector que causó esta llamada al método (la variable _cmd
está realmente disponible en todo Métodos Objective-C, pruébelo), y el resto se considera variadic. Usted necesita para convertir las variables IMP
en la firma de función adecuada porque la convención de llamadas para funciones C variables no siempre coincide con la convención de llamadas de método Objective-C (la llamada de método Objective-C es la convención de llamada de función estándar para su compilador, probablemente cdecl
o la convención de llamadas amd64, y la convención de llamadas variadas es no siempre lo mismo). Un reinterpret_cast
podrá hacerlo.
Aquí hay un código que armé para propósitos similares. Utiliza plantillas variadas de C++ 11 para ayudar a obtener la firma de función adecuada.
#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));
}
también se ocupan de que su caso no es nil
antes de utilizar la llamada a la función, porque nil
comprobación es manejado por el tiempo de ejecución de Objective-C. En este caso, lo estamos eludiendo.
Realizar un seguimiento de un objeto y un SEL
Uso -[NSObject performSelector:]
para realizar su devolución de llamada. Básicamente es una versión más simple de la solución de tiempo de ejecución Objective-C.
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));
}
Envolviendo su llamada dentro de una función de C++
Creo que éste en realidad no necesita ningún ejemplo. Cree una función que acepte su tipo de objeto como primer parámetro y llame al método que desee. De forma similar a la solución SEL
, debe realizar un seguimiento por separado de la función a llamar y el objeto al que se debe llamar.
ni siquiera necesita la implementación. Siempre puede usar 'objc_msgSend' en lugar de la implementación – user102008
True. En ese caso, llevaría el selector en lugar del puntero del método. – zneak
No. Con su IMP, tendría que llevar el selector de todos modos. Entonces es lo mismo, excepto que ahora no necesita obtener un IMP. – user102008