web-dev-qa-db-ja.com

-performSelectorの使用:vs.メソッドの呼び出し

私はまだObjective-Cに慣れていないのですが、次の2つのステートメントの違いは何ですか?

[object performSelector:@selector(doSomething)]; 

[object doSomething];
111
TheGambler

基本的にperformSelectorを使用すると、指定したオブジェクトでセレクターを呼び出すセレクターを動的に決定できます。つまり、セレクターは実行前に決定する必要はありません。

したがって、これらは同等ですが:

[anObject aMethod]; 
[anObject performSelector:@selector(aMethod)]; 

2番目の形式では、これを行うことができます。

SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];

メッセージを送信する前に。

189
ennuikiller

質問のこの非常に基本的な例では、

[object doSomething];
[object performSelector:@selector(doSomething)]; 

何が起こるかに違いはありません。 doSomethingはオブジェクトによって同期的に実行されます。 「doSomething」のみが非常に単純なメソッドであり、何も返さず、パラメーターを必要としません。

次のような、もう少し複雑なものでしたか?

(void)doSomethingWithMyAge:(NSUInteger)age;

[object doSomethingWithMyAge:42];

パラメータを持つすべてのバリアントはオブジェクトパラメータのみを受け入れるため、「performSelector」のどのバリアントでも呼び出せなくなりました。

ここのセレクタは「doSomethingWithMyAge:」ですが、

[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];  

単にコンパイルしません。 NSNumber:42の代わりに@(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)戻り値が使用されます。

何とかこれをカバーしたい...

13
Motti Shneor

@ennuikillerがスポットです。基本的に、動的に生成されたセレクターは、コードをコンパイルするときに呼び出すメソッドの名前を知らない(通常はおそらくできない)場合に役立ちます。

重要な違いの1つは、 -performSelector: およびフレンド( マルチスレッドおよび遅延バリアント を含む)は、0〜2個のパラメータを持つメソッドで使用するように設計されているという点で多少制限されています。たとえば、 -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation: 6つのパラメーターを使用し、NSStringを返すのはかなり扱いにくく、提供されたメソッドではサポートされていません。

11
Quinn Taylor

セレクターは、他の言語の関数ポインターに少し似ています。コンパイル時に実行時に呼び出すメソッドがわからない場合に使用します。また、関数ポインターのように、呼び出しの動詞部分のみをカプセル化します。メソッドにパラメーターがある場合は、それらも渡す必要があります。

NSInvocationも同様の目的を果たしますが、より多くの情報を結び付ける点が異なります。動詞部分だけでなく、ターゲットオブジェクトとパラメーターも含まれます。これは、現在ではなく将来、特定のパラメーターを使用して特定のオブジェクトのメソッドを呼び出す場合に便利です。適切なNSInvocationをビルドして、後で起動できます。

3