7

_cmd私はこのトリックに出くわしました:

-(void)methodToBeRunOnMainThreadWithObj:(id)object {
    if (![NSThread isMainThread) {
        [self performSelectorOnMainThread:_cmd withObject:object]
    } else {
        // ... method body
    }
}

これは、メソッドがメインスレッドで確実に実行されるようにするための信頼できる方法ですか?

4

2 に答える 2

7

これは機能しますが、少しアンチパターンです。メソッドが呼び出されたスレッドがメインスレッドでない場合、私が行うことはエラーをスローすることです。メソッドが正しいスレッドで呼び出されるようにするのは呼び出し元の責任です。これらの種類のハッキングは、醜いコードを助長するだけです。さらに、これに依存している場合、このメソッドを呼び出すたびに、突然、メッセージディスパッチのオーバーヘッドが2倍になります。

発信者の動作を本当に変更できない場合は、次のことを試すことができます。

-(void)methodToBeRunOnMainThreadWithObj:(id)object {
    dispatch_sync(dispatch_get_main_queue(), ^{
        // code goes here
    });
}

これにより、ディスパッチブロック内のすべてのコードがメインスレッドで実行され、メソッドは完了するまで戻りません。メソッドをすぐに返す場合は、代わりに使用できますdispatch_async。を使用するdispatch_syncと、void以外の戻り型を持つメソッドでもこのトリックを使用できます。

このコードには、非オブジェクト型(intなど)の引数を持つメソッドをサポートするという追加の利点もあります。また、任意の数の引数を持つメソッドをサポートしますが、performSelector:withObject:その兄弟メソッドは限られた数の引数のみをサポートします。別の方法はオブジェクトを設定するNSInvocationことであり、それらは面倒です。

これには、プラットフォームにGrand Central Dispatch(GCD)が必要であることに注意してください。

于 2012-11-02T06:20:49.013 に答える
3

_cmd_cmdによって指定されたセレクターがドキュメントで指定された定義/署名と一致する限り、転送は問題ありません。「メソッドは重要な戻り値を持たず、タイプidの単一の引数を取るか、引数をとらない必要があります。」。一致しない場合は、未定義動作を想定する必要があります。また、110%の安全性と抽象マシンに準拠するために、戻り型はid(またはいくつかのobjc型)である必要があり、結果は所有する参照を返さないようにする必要があります。

于 2012-11-02T06:25:47.497 に答える