あなたはいくつかの選択肢があります。
ブロックの使用
ブロックを使用してコールバックの仕事を伝えることができます。コールバック関数にパラメータを渡すことなくコードを呼び出すことができるので、これはおそらく最も簡単な解決策です。ブロックはCとそのすべてのスーパーセットでClangで動作し、Clang ++はブロックとラムダ間の暗黙のキャストを許可します。代わりに、関数ポインタのファンクタ(または単にブロック、それは簡単です場合)を受け入れるようにC++の端にいくつかの手直しが必要になる場合があります
#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];
});
}
。
ブロックはクロージャを作成するので、そのような作業には非常に便利です。
ブロックは、C、C++、Objective-CのApple拡張です。それらについての詳細はhereを参照してください。
はあなたの選択の関数ポインタにアクセスするためのObjective-Cランタイムを使用し
を呼び出したいメソッドに関数ポインタを取得するためのObjective-Cランタイムを使用してください。これはもっと退屈で、3つの変数(メソッドを呼び出すオブジェクト、使用するセレクタ、メソッドの実装)を追跡する必要がありますが、Objective-Cを使用できない場合でも実際に機能します構文。
Objective-Cのメソッドの実装は、このシグネチャを持つ関数ポインタです:self
は、あなたが期待するものである
typedef void (*IMP)(id self, SEL _cmd, ...);
は、_cmd
は、このメソッドの呼び出しを引き起こしたセレクタです(_cmd
変数はすべてで実際に利用可能ですObjective-Cの方法を試してみてください)、残りはバリデーションとみなされます。 IMP
の変数を適切な関数シグネチャにキャストする必要があります。これは、variadic C関数の呼び出し規約が、Objective-Cメソッド呼び出しの呼び出し規則と常に一致するわけではないからです(Objective-Cメソッド呼び出しは、おそらくcdecl
またはamd64呼び出し規約のいずれかであり、可変呼び出し規約はであり、必ずしもと同じではありません。 reinterpret_cast
がそれを行うことができます。
ここに、私が似た意図でまとめたコードがあります。これは、適切な関数シグネチャを得るのを助けるためにC++ 11バリデーションテンプレートを使用します。
#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));
}
またnil
チェックはObjective-Cランタイムによって処理されるので、あなたのインスタンスは、関数呼び出しを使用する前にnil
ないように注意してください。この場合、私たちはそれをバイパスしています。
あなたのコールバックを実行するために、オブジェクトとSEL
利用-[NSObject performSelector:]
を追跡します。基本的にObjective-Cランタイムソリューションのより単純なバージョンです。 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));
}
私はこの1つは本当にすべての例を必要としないと思います。最初のパラメータとしてオブジェクト型を受け入れ、それに必要なメソッドを呼び出す関数を作成します。 SEL
ソリューションと同様に、呼び出す関数と呼び出すオブジェクトを個別に追跡する必要があります。
実装する必要はありません。 – user102008
の実装の代わりに 'objc_msgSend'を使うことができます。その場合、メソッドポインタの代わりにセレクタを持ちます。 – zneak
いいえあなたのIMPで、あなたはとにかくセレクターを運ぶ必要があります。だから、同じことですが、今はIMPを取得する必要はありません。 – user102008