私はまだObjective-Cに慣れていないので、次の2つのステートメントの違いは何ですか?
[object performSelector:@selector(doSomething)];
[object doSomething];
私はまだObjective-Cに慣れていないので、次の2つのステートメントの違いは何ですか?
[object performSelector:@selector(doSomething)];
[object doSomething];
基本的に performSelector を使用すると、特定のオブジェクトでどのセレクターを呼び出すかを動的に決定できます。つまり、実行前にセレクターを決定する必要はありません。
したがって、これらは同等ですが:
[anObject aMethod];
[anObject performSelector:@selector(aMethod)];
2 番目の形式では、これを行うことができます。
SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
メッセージを送信する前に。
質問のこの非常に基本的な例では、
[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 型を想定しているため、どちらも役に立ちません。
さらに、パラメータが 2 つまでの performSelector バリアントがあり、それ以上はありません。多くの場合、メソッドにはさらに多くのパラメーターがあります。
私は、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 つは、-performSelector:
and フレンド (マルチスレッド バリアントと遅延バリアントを含む) は、0 ~ 2 個のパラメーターを持つメソッドで使用するように設計されているという点で、ある程度制限されていることです。たとえば、-outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:
6 つのパラメーターで呼び出して を返すのNSString
はかなり扱いにくく、提供されているメソッドではサポートされていません。
セレクターは、他の言語の関数ポインターに少し似ています。実行時に呼び出すメソッドがコンパイル時にわからない場合に使用します。また、関数ポインタと同様に、呼び出しの動詞部分のみをカプセル化します。メソッドにパラメーターがある場合は、それらも渡す必要があります。
AnNSInvocation
は同様の目的を果たしますが、より多くの情報を結合する点が異なります。動詞部分だけでなく、対象オブジェクトとパラメータも含まれます。これは、現在ではなく将来、特定のパラメータを使用して特定のオブジェクトのメソッドを呼び出したい場合に便利です。適切なものを作成して、NSInvocation
後で起動できます。
この 2 つには、もう 1 つの微妙な違いがあります。
[object doSomething]; // is executed right away
[object performSelector:@selector(doSomething)]; // gets executed at the next runloop
これはAppleのドキュメントからの抜粋です
"performSelector:withObject:afterDelay: 次の実行ループ サイクル中およびオプションの遅延期間の後に、指定されたセレクターを現在のスレッドで実行します。次の実行ループ サイクルまで待機してセレクターを実行するため、これらのメソッドは、現在実行中のコード。キューに入れられた複数のセレクターは、キューに入れられた順序で次々に実行されます。」