104

ブロックと完了ブロックを受け入れるメソッドがあります。最初のブロックはバックグラウンドで実行する必要がありますが、完了ブロックはメソッドが呼び出されたキューで実行する必要があります。

後者については、私は常に を使用dispatch_get_current_queue()していましたが、iOS 6 以降では非推奨になっているようです。代わりに何を使用すればよいですか?

4

7 に答える 7

65

「呼び出し元がオンになっているキューで実行する」というパターンは魅力的ですが、最終的には良いアイデアではありません。そのキューは、優先度の低いキュー、メイン キュー、または奇妙なプロパティを持つその他のキューである可能性があります。

これに対する私のお気に入りのアプローチは、「完了ブロックは、x、y、z のプロパティを持つ実装定義のキューで実行される」と言い、呼び出し元がそれ以上の制御を必要とする場合は、ブロックを特定のキューにディスパッチさせることです。指定するプロパティの典型的なセットは、「シリアル、再入不可、および他のアプリケーションから見えるキューに関して非同期」のようなものです。

** 編集 **

Catfish_Man は以下のコメントに例を示しました。私はそれを彼の回答に追加しています。

- (void) aMethodWithCompletionBlock:(dispatch_block_t)completionHandler     
{ 
    dispatch_async(self.workQueue, ^{ 
        [self doSomeWork]; 
        dispatch_async(self.callbackQueue, completionHandler); 
    } 
}
于 2012-11-05T19:07:57.790 に答える
27

これは、あなたが説明しているAPIにとって根本的に間違ったアプローチです。API が実行するブロックと完了ブロックを受け入れる場合、次の事実が当てはまる必要があります。

  1. 「実行するブロック」は内部キューで実行する必要があります。たとえば、キュ​​ーは API に対してプライベートであり、したがって完全にその API の制御下にあります。これに対する唯一の例外は、ブロックがメイン キューまたはグローバル同時キューの 1 つで実行されることを API が明確に宣言している場合です。

  2. #1 と同じ仮定が成り立たない限り、完了ブロックは常にタプル (キュー、ブロック) として表現する必要があります。たとえば、完了ブロックは既知のグローバル キューで実行されます。さらに、完了ブロックは、渡されたキューで非同期にディスパッチする必要があります。

これらは単なる文体上のポイントではなく、API がデッドロックやその他のエッジケースの動作から安全であるためには完全に必要です。:-)

于 2012-11-06T05:20:57.150 に答える
15

他の答えは素晴らしいですが、私にとって答えは構造的です。シングルトンにある次のようなメソッドがあります。

- (void) dispatchOnHighPriorityNonMainQueue:(simplest_block)block forceAsync:(BOOL)forceAsync {
    if (forceAsync || [NSThread isMainThread])
        dispatch_async_on_high_priority_queue(block);
    else
        block();
}

これには次の 2 つの依存関係があります。

static void dispatch_async_on_high_priority_queue(dispatch_block_t block) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block);
}

typedef void (^simplest_block)(void); // also could use dispatch_block_t

そうすれば、他のスレッドでディスパッチする呼び出しを集中化できます。

于 2013-08-12T23:21:34.213 に答える
12

dispatch_get_current_queueそもそも使用には注意が必要です。ヘッダーファイルから:

デバッグとロギングの目的でのみ推奨:

それがグローバルキューの1つであるか、コード自体が作成したキューでない限り、コードは返されたキューについていかなる仮定もしてはなりません。そのキューがdispatch_get_current_queue()によって返されるキューでない場合、コードはキューへの同期実行がデッドロックから安全であると想定してはなりません。

次の2つのいずれかを実行できます。

  1. 最初に投稿したキューへの参照を保持し(を介して作成した場合dispatch_queue_create)、それ以降はそれを使用します。

  2. を介してシステム定義のキューを使用し、使用しているキューをdispatch_get_global_queue追跡します。

事実上、以前は自分がいるキューを追跡するためにシステムに依存していましたが、自分でそれを行う必要があります。

于 2012-11-05T18:18:39.740 に答える
4

キュー内での比較が必要な場合は、キューをラベルまたは指定で比較できます。これを確認してください https://stackoverflow.com/a/23220741/1531141

于 2014-04-22T13:55:44.997 に答える