回答:
基本的に、performSelectorを使用すると、指定したオブジェクトのセレクターを呼び出すセレクターを動的に決定できます。つまり、ランタイムの前にセレクターを決定する必要はありません。
したがって、これらは同等ですが:
[anObject aMethod];
[anObject performSelector:@selector(aMethod)];
2番目の形式では、これを行うことができます。
SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
メッセージを送信する前に。
performSelector:
は、クラスにtarget-actionを実装する場合にのみ行うものです。兄弟performSelectorInBackground:withObject:
とperformSelectorOnMainThread:withObject:waitUntilDone:
は、しばしばより便利です。バックグラウンドスレッドを生成し、バックグラウンドスレッドからメインスレッドに結果をコールバックします。
performSelector
コンパイル警告を抑制するのにも役立ちます。メソッドが存在することがわかっている場合(を使用した後などrespondsToSelector
)、Xcodeが「応答しない可能性があります」と表示されなくなりyour_selector
ます。警告の本当の原因を見つける代わりに、それを使用しないでください。;)
質問のこの非常に基本的な例では、
[object doSomething];
[object performSelector:@selector(doSomething)];
何が起きるかに違いはありません。doSomethingはオブジェクトによって同期的に実行されます。"doSomething"だけが非常に単純なメソッドであり、何も返さず、パラメーターを必要としません。
それは次のようなもう少し複雑なものでしたか?
(void)doSomethingWithMyAge:(NSUInteger)age;
[object doSomethingWithMyAge:42];なので、状況は複雑になります。
パラメータを持つすべてのバリアントはオブジェクトパラメータのみを受け入れるため、「performSelector」のバリアントで呼び出すことはできなくなりました。
ここでのセレクターは "doSomethingWithMyAge:"ですが、
[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];
単にコンパイルされません。42ではなくNSNumber:@(42)を渡しても、メソッドではオブジェクトではなく基本的なCタイプが想定されるため、効果がありません。
さらに、performSelectorバリアントには最大2つのパラメーターがあり、それ以上はありません。メソッドには多くの場合、さらに多くのパラメーターがあります。
私は、performSelectorの同期バリアントですが、
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
常にオブジェクトを返します。単純なBOOLまたはNSUIntegerも返すことができました。
前の回答で説明したように、performSelectorの2つの主な用途の1つは、実行するメソッドの名前を動的に作成することです。例えば
SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age");
[object performSelector:method];
もう1つは、現在の実行ループで後で実行される、メッセージをオブジェクトに非同期でディスパッチすることです。このために、他にいくつかのperformSelectorバリアントがあります。
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;
(はい、NSThread、NSRunLoop、NSObjectなどのいくつかのFoundationクラスのカテゴリから収集しました)
各バリアントには独自の特別な動作がありますが、すべてが共通して何かを共有します(少なくともwaitUntilDoneがNOに設定されている場合)。「performSelector」呼び出しはすぐに返され、オブジェクトへのメッセージはしばらくしてから現在の実行ループにのみ配置されます。
実行が遅延するため、当然、セレクターのメソッドから返される戻り値はありません。したがって、これらすべての非同期バリアントでは-(void)戻り値が返されます。
なんとかカバーしてくれたらいいのに...
@ennuikillerが登場しました。基本的に、動的に生成されたセレクターは、コードをコンパイルするときに呼び出すメソッドの名前がわからない(通常はわからない)場合に役立ちます。
主な違いの1つは、0から2のパラメーターを持つメソッドで使用するように設計されているという点で、-performSelector:
(マルチスレッドや遅延のバリアントを含む)友人は多少制限されていることです。たとえば、-outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:
6つのパラメーターを使用して呼び出し、それを返すのNSString
は非常に扱いにくく、提供されたメソッドではサポートされていません。
NSInvocation
オブジェクトを使用する必要があります。
performSelector:
フレンドはすべてオブジェクト引数を取ります。つまりsetAlphaValue:
、その引数は浮動小数点であるため、それらを使用して(たとえば)を呼び出すことはできません。
セレクターは、他の言語の関数ポインターに少し似ています。コンパイル時にどのメソッドを実行時に呼び出すかわからない場合に使用します。また、関数ポインターと同様に、呼び出しの動詞部分のみをカプセル化します。メソッドにパラメータがある場合は、それらも渡す必要があります。
アンは、NSInvocation
それが一緒に多くの情報を結合することを除いて、同様の目的を果たします。動詞部分だけでなく、ターゲットオブジェクトとパラメーターも含まれます。これは、現在ではなく将来、特定のパラメーターを使用して特定のオブジェクトのメソッドを呼び出す場合に便利です。適切なものNSInvocation
を作成して、後で起動できます。
2つの間に別の微妙な違いがあります。
[object doSomething]; // is executed right away
[object performSelector:@selector(doSomething)]; // gets executed at the next runloop
これはアップルのドキュメントからの抜粋です
"performSelector:withObject:afterDelay:次の実行ループサイクルの間、およびオプションの遅延期間の後、現在のスレッドで指定されたセレクターを実行します。セレクターを実行する次の実行ループサイクルまで待機するため、これらのメソッドは、現在実行中のコード。複数のキューに入れられたセレクターは、キューに入れられた順序で次々に実行されます。」
performSelector:withObject:afterDelay:
ですが、質問とスニペットはを使用していますがperformSelector:
、これはまったく別の方法です。そのドキュメントから:<quote>このperformSelector:
方法は、aSelector
メッセージを受信者に直接送信することと同等です。</ quote>
performSelector/performSelector:withObject/performSelector:withObject:afterDelay
すべて同じように振る舞ったのは間違いでした。