[[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 件のコメント:
コメントを投稿