そんなに使い所はなさそうだけど。
performSelector メソッドのように、SEL 型のオブジェクトを引数に指定しないといけない場合、メソッドは予め用意しておく必要がある。
[self performSelector:@selector(hoge)];
この場合は hoge メソッドを先に定義しておかないといけない。
実はこれがけっこう面倒だと感じることが多いので、
[self performBlock:^{ 処理; }];
と書けるようにメソッドを用意してしまえばいいのだけど、(いつも用意するんだけど)
そもそも、@selector(hoge) の部分をその場で作れないのか?
と疑問に思ったのが始まりで、以下が試した結果。
// とりあえずなんか適当なブロックを作る
void (^hogeBlock)(void) = ^(void)
{
NSLog(@"hoge");
};
// 文字列から SEL 型を作っておく
SEL sel = NSSelectorFromString(@"hoge");
// ブロックから IMP 型を作っておく
IMP imp = imp_implementationWithBlock(hogeBlock);
// class_addMethod でセレクタとメソッドを登録する
// 下の場合は、ViewController クラスに hoge というセレクタ名で、
// 処理の内容は上で作った hogeBlock で登録する
class_addMethod([ViewController class], sel, imp, "v@");
ここまでの処理でメソッドが定義された状態になるので、
[self hoge]; // hoge
[self performSelector:@selector(hoge)]; // hoge
で hogeBlock が実行できるようになる。
hogeBlock では1つも引数を書かなかったが、実は暗黙で自身のオブジェクトを
第一引数で渡しているらしいので、
void (^piyoBlock)(id obj) = ^(id obj)
{
NSLog(@"piyo");
};
SEL sel = NSSelectorFromString(@"piyo");
IMP imp = imp_implementationWithBlock(piyoBlock);
class_addMethod([ViewController class], sel, imp, "v@");
上のように Block に引数を書いていても SEL 型を作るところで【コロン】なくてOK。
[self piyo]; // piyo
[self performSelector:@selector(piyo)]; // piyo
引数がある場合は、SEL 型を作るところで【コロン】を追加し、
Block で第2引数から1つ目の引数を書けばよい。
よって、1つだけ引数を受け取る fuga メソッドを作る場合は、
void (^fugaBlock)(id, NSString *) = ^(id selfInstance, NSString *str)
{
NSLog(@"fuga : %@", str);
};
SEL sel = NSSelectorFromString(@"fuga:");
IMP imp = imp_implementationWithBlock(fugaBlock);
class_addMethod([ViewController class], sel, imp, "v@:*");
のように、Block のところで第2引数に1つ目の引数を書き、
SEL 型を作るところで【コロン】を付ける。
呼び出しはこんな感じ。
[self fuga:@"あいうえお"]; // fuga : あいうえお
[self performSelector:@selector(fuga:) withObject:@"あいうえお"]; // fuga : あいうえお
複数引数の場合は、SEL型を作るところで、複数のコロンで引数の部分を区切ればよい。
void (^hogehogeBlock)(id, NSString *, NSString *) = ^(id selfInstance, NSString *str1, NSString *str2)
{
NSLog(@"hogehoge : str1 = %@, str2 = %@", str1, str2);
};
SEL sel = NSSelectorFromString(@"hogehogeWithStr1:andStr2:");
IMP imp = imp_implementationWithBlock(hogehogeBlock);
class_addMethod([ViewController class], sel, imp, "v@:**");
[self hogehogeWithStr1:@"あいうえお" andStr2:@"かきくけこ"]; // hogehoge : str1 = あいうえお, str2 = かきくけこ
と、まぁ、こんな感じでその場でメソッド作れますよ、という話でした。
class_addMethod 関数の第4引数の値についてはよくわからなくて、
NULL でも空文字でも何を指定してもうまく動いてしまった。。。
詳しくはこの辺りに書いてあるんだけど、正解がイマイチわからない・・・。
Objective-C Runtime Reference
Type Encodings