53
54

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

BlockからSelector(メソッド)を作る

Last updated at Posted at 2013-01-13

そんなに使い所はなさそうだけど。

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

53
54
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
53
54

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?