web-dev-qa-db-ja.com

iPhone-Grand Central Dispatchメインスレッド

私は自分のアプリで成功を収め、大規模なディスパッチを使用してきましたが、次のようなものを使用することの本当の利点は何だろうと思いました。

dispatch_async(dispatch_get_main_queue(), ^{ ... do stuff

あるいは

dispatch_sync(dispatch_get_main_queue(), ^{ ... do stuff

つまり、どちらの場合でも、アプリが実行される正確な場所でメインスレッドで実行されるブロックを起動しているため、負荷を軽減するのに役立ちません。最初のケースでは、ブロックを実行するタイミングを制御できません。ブロックを起動してから0.5秒後にブロックが実行されるケースを見てきました。 2番目のケースは、

[self doStuff];

右?

君たちはどう思う?.

144
SpaceDog

メインキューへのブロックのディスパッチは、通常、バックグラウンドキューから行われ、バックグラウンド処理が完了したことを通知します。

- (void)doCalculation
{
    //you can use any string instead "com.mycompany.myqueue"
    dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);

    dispatch_async(backgroundQueue, ^{
        int result = <some really long calculation that takes seconds to complete>;

        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateMyUIWithResult:result];
        });    
    });
}

この場合、バックグラウンドキューで長い計算を行っているため、計算が完了したらUIを更新する必要があります。通常、UIの更新はメインキューから行う必要があるため、2番目のネストされたdispatch_asyncを使用してメインシグナルに「シグナル」を返します。

メインキューにディスパッチする他の例もおそらくありますが、一般的にはこの方法で行われます。つまり、バックグラウンドキューにディスパッチされたブロック内からネストされます。

  • バックグラウンド処理が終了-> UIを更新
  • バックグラウンドキューで処理されたデータのチャンク->メインキューに次のチャンクを開始するように通知する
  • バックグラウンドキューの着信ネットワークデータ->メッセージが到着したことをメインキューに通知する
  • などなど

メインキューにディスパッチしたい理由についてfromメインキュー...まあ、一般的には、おそらく次の時間に何かをするためにいくつかの作業をスケジュールするためにそれを行うことはないでしょう実行ループ。

293

メインスレッドからメインキューにブロックをディスパッチしますcanが便利です。メインキューがキューに入れられた他のブロックを処理する機会を与えるので、他のすべての実行をブロックするだけではありません。

たとえば、多数の同時接続を処理する基本的に単一のスレッドサーバーを作成できます。キュー内の個々のブロックに時間がかかりすぎない限り、サーバーは新しい要求に応答し続けます。

プログラムがイベントに応答するために一生を費やすだけなら、これは非常に自然なことです。メインキューで実行するようにイベントハンドラーを設定し、dispatch_main()を呼び出すだけで、スレッドセーフについてまったく心配する必要がなくなる場合があります。

15
bames53

うまくいけば、dispatch_asyncとdispatch_syncの違いについて疑問に思っているという点で、あなたの質問を正しく理解していますか?

dispatch_async

ブロックを非同期でキューにディスパッチします。つまり、ブロックをキューに送信し、メソッド内の残りのコードの実行を続行する前にブロックが戻るのを待機しません。

dispatch_sync

ブロックをキューに同期的にディスパッチします。これにより、ブロックの実行が完了するまで、メソッド内の残りのコードが実行されなくなります。

私は主にバックグラウンドキューにdispatch_asyncを使用して、メインキューからの作業を取得し、デバイスにある可能性のある追加のコアを利用しています。 UIを更新する必要がある場合は、dispatch_asyncをメインスレッドに追加します。

がんばろう

11
timthetoolman

便利な1つの場所は、長時間の操作の前にスピナーを設定するなどのUIアクティビティです。

- (void) handleDoSomethingButton{

    [mySpinner startAnimating];

    (do something lengthy)
    [mySpinner stopAnimating];
}

長い間メインスレッドをブロックし、UIKitにスピナーを実際に起動させないため、動作しません。

- (void) handleDoSomethingButton{
     [mySpinner startAnimating];

     dispatch_async (dispatch_get_main_queue(), ^{
          (do something lengthy)
          [mySpinner stopAnimating];
    });
}

実行ループに制御を戻し、UIの更新をスケジュールし、スピナーを開始し、ディスパッチキューから次のものを取得します。これが実際の処理です。処理が完了すると、アニメーション停止が呼び出され、実行ループに戻り、UIが停止で更新されます。

8
weaselfloss1

Swift 3、4&5

メインスレッドでコードを実行する

DispatchQueue.main.async {
    // Your code here
}
7
Niall Kiddle

非同期とは非同期を意味するため、ほとんどの場合それを使用する必要があります。メインスレッドでsyncを呼び出さないでください。タスクが完了するまでUIがロックされます。あなたはSwiftでこれを行うためのより良い方法です:

runThisInMainThread { () -> Void in
    // Run your code like this:
    self.doStuff()
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

それは私のレポの標準機能として含まれています、それをチェックしてください: https://github.com/goktugyil/EZSwiftExtensions

1
Esqarrouth