[[AClass alloc] initWithTarget:self selector:@selector(hello:)];などとしておいて、後で AClass から [self hello:…]をコールしてもらうということがありますが、これってどうやって実現しているんでしょうか?
方法はいくつかありますが、そのうちの一つが NSInvocation を使うという方法です。
cocos2d の内部でも使われていました。
NSInvocation オブジェクトの作成は以下のようになります。
- (id)initWithTarget:(id)tar selector:(SEL)sel { ... 何かの処理 invocation = nil; // クラスメソッド NSInvocation *invocation if (tar && sel) { // selector(メソッド)のシグネチャを作成 NSMethodSignature *sig = [tar methodSignatureForSelector:sel]; if (sig) { invocation = [[NSInvocation invocationWithMethodSignature:sig] retain]; [invocation setTarget:tar]; [invocation setSelector:sel]; } } ... 何かの処理 }まず、引数の tar と sel を使用して、メソッドのシグネチャを作成します。
methodSignatureForSelector: は NSObject クラスのメソッドです。
tar クラス に sel メソッドが無ければ nil が返されます。
設定したメソッドを実行するには以下のようにします。
if (invocation) { [invocation setArgument:&arg1 atIndex:2]; [invocation invoke]; }arg1 は 例で言うと、target オブジェクトの hello メソッドに渡す引数です。
変数に&を付けてポインタ渡しするのと、引数のインデックスが2から始まることに注意です。
以下のように、引数を2つ以上必要な場合も大丈夫。
[[AClass alloc] initWithTarget:self selector:@selector(hello:world:)];インデックスを指定して、いくつでも対応できます。
if (invocation) { [invocation setArgument:&arg1 atIndex:2]; [invocation setArgument:&arg2 atIndex:3]; [invocation invoke]; }
メソッドが返り値を持っている場合は、NSInvocation オブジェクトから取得します。
int value; [invocation invoke]; [invocation getReturnValue:&value]; // int型の返り値の場合
似たような機能の実現方法としてデリゲートがありますが、プロトコルを定義しなければならず、そのようなおおげさな方法をとるまでもない時に NSInvocation は重宝します。
0 件のコメント:
コメントを投稿