web-dev-qa-db-ja.com

Objective-Cで実行時にセレクターを動的に作成するにはどうすればよいですか?

コンパイル時に@selector(MyMethodName:)を使用してSELを作成する方法は知っていますが、NSStringからセレクターを動的に作成したいです。これも可能ですか?

私は何ができますか:

_SEL selector = @selector(doWork:);
[myobj respondsToSelector:selector];
_

私がやりたいこと:(擬似コード、これは明らかに機能しません)

_SEL selector = selectorFromString(@"doWork");
[myobj respondsToSelector:selector];
_

私はApple APIドキュメントを検索しましたが、コンパイル時の@selector(myTarget:)構文に依存しない方法を見つけていません。

92
craigb

私はObjective-Cプログラマーではなく、単なるシンパサイザーですが、おそらく NSSelectorFromString が必要なものです。 Runtime Reference で明示的に言及されていますが、これを使用して文字列をセレクターに変換できます。

180
Torsten Marek

XCodeのドキュメントによると、psuedocodeは基本的に正しく機能します。

@selector()ディレクティブを使用して、コンパイル時にSEL変数に値を割り当てるのが最も効率的です。ただし、場合によっては、実行時にプログラムで文字列をセレクターに変換する必要があります。これは、NSSelectorFromString関数を使用して実行できます。

setWidthHeight = NSSelectorFromString(aBuffer);

編集:残念、遅すぎる。 :P

40
Josh Gagnon

それは少し複雑です以前の回答者の答えが示唆するよりも...本当にあなたが本当にselectorを作成したいなら。 ..あなたが「周りに置いている」「ただ一つを呼ぶ」だけではありません...

「新しい」メソッドによって呼び出される関数ポインタを作成する必要があります。したがって、[self theMethod:(id)methodArg];のようなメソッドの場合、次のように記述します。

void (^impBlock)(id,id) = ^(id _self, id methodArg) { 
     [_self doSomethingWith:methodArg]; 
};

次に、IMPブロックを動的に生成する必要があります。今回は、「self」、SEL、および引数を渡して...

void(*impFunct)(id, SEL, id) = (void*) imp_implementationWithBlock(impBlock);

吸盤全体の正確なメソッドシグネチャ(この場合は"v@:@"、void戻り値、オブジェクト呼び出し元、オブジェクト引数)

 class_addMethod(self.class, @selector(theMethod:), (IMP)impFunct, "v@:@");

この種の [runtime shenanigans]の良い例が、私のリポジトリの1つにあります。ここにあります。

11
Alex Gray

これはずっと前から回答されてきましたが、それでも共有したいと思います。これもsel_registerNameを使用して実行できます。

質問のコード例は次のように書き換えることができます。

SEL selector = sel_registerName("doWork:");
[myobj respondsToSelector:selector];
4
Krypton