Sie haben ein paar Optionen.
Mit Blöcke
können Sie Blöcke benutzen, um Ihre Rückruf Arbeit zu vermitteln. Dies ist wahrscheinlich die einfachste Lösung, da Sie Ihren Code aufrufen können, ohne einen Parameter an die Callback- "Funktion" übergeben zu müssen. Blöcke arbeiten in C und alle ihre Supersätze mit Clang, und Clang ++ erlaubt sogar implizite Umwandlungen zwischen Blöcken und 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];
});
}
, dass einige Nacharbeiten an dem C++ Ende erfordern könnte functors (oder nur blockiert, wenn es einfacher ist) zu akzeptieren, anstatt Funktionszeiger.
Da Blöcke Schließungen erzeugen, sind sie sehr praktisch für diese Art von Arbeiten.
Blöcke sind eine Apple-Erweiterung für C, C++ und Objective-C. Sehen Sie mehr über sie .
Verwenden Sie die Objective-C-Laufzeit der Funktionszeiger auf die Methode, die Sie
Verwenden Sie die Objective-C-Laufzeit aufgerufen werden sollen erwerben die Funktionszeiger Ihrer Wähler zuzugreifen. Dies ist mühsamer und erfordert, dass Sie drei Variablen (das Objekt, für das die Methode aufgerufen wird, den zu verwendenden Selektor und die Methodenimplementierung) im Auge behalten, aber es funktioniert sogar, wenn Sie das Objective-C nicht verwenden können Syntax.
Objective-C-Methode Implementierungen Funktionszeiger mit dieser Signatur sind:
typedef void (*IMP)(id self, SEL _cmd, ...);
Wo self
ist das, was man erwarten würde, _cmd
ist der Wähler, die diese Methode Aufruf verursacht (die _cmd
Variable ist in allen tatsächlich verfügbar Objective-C-Methoden, versuchen Sie es), und der Rest gilt als variadic. Sie müssenIMP
Variablen in die richtige Funktion Signatur umwandeln, da die Aufrufkonvention für variadic C-Funktionen nicht immer die aufrufende Konvention für Objective-C-Methodenaufrufe (die Objective-C-Methode Aufruf ist die Standardfunktion Aufruf Konvention für Ihre Compiler, wahrscheinlich entweder cdecl
oder die Aufrufkonvention amd64, und die variadic Aufrufkonvention ist nicht immer das gleiche). A reinterpret_cast
wird dazu in der Lage sein.
Hier ist ein Code, den ich für ähnliche Absichten zusammengestellt habe. Es verwendet C++ 11 variadische Vorlagen, um die korrekte Funktionssignatur zu erhalten.
#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));
}
Nehmen Sie auch darauf, dass Ihr Beispiel ist nicht nil
vor dem Funktionsaufruf zu verwenden, da nil
Prüfung durch die Objective-C-Laufzeit behandelt wird. In diesem Fall umgehen wir es.
Behalten eines Objekts und ein SEL
Verwenden -[NSObject performSelector:]
Ihren Rückruf auszuführen. Im Grunde eine einfachere Version der Objective-C-Laufzeitlösung.
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));
}
Wrapping Ihren Anruf innerhalb einer C++ Funktion
Ich denke, das man nicht wirklich kein Beispiel braucht. Erstellen Sie eine Funktion, die Ihren Objekttyp als ersten Parameter akzeptiert, und rufen Sie die gewünschte Methode auf. Ähnlich wie bei der SEL
Lösung müssen Sie dann separat die zu rufende Funktion und das Objekt, auf dem sie aufgerufen werden, verfolgen.
Sie brauchen nicht einmal die Implementierung zu bekommen. Sie können immer 'objc_msgSend' anstelle der Implementierung – user102008
True verwenden. In diesem Fall würden Sie den Selektor anstelle des Methodenzeigers verwenden. – zneak
Nein. Mit Ihrem IMP müssten Sie den Selektor trotzdem tragen. Es ist also dasselbe, nur dass Sie jetzt kein IMP benötigen. – user102008