web-dev-qa-db-ja.com

メインスレッドでタスクを実行するGCD

任意のスレッドからのコールバックがあります。このコールバックを取得したら、メインスレッドで特定のタスクを実行します。

すでにメインスレッドにいるかどうかを確認する必要がありますか?または、以下のコードを呼び出す前にこのチェックを実行しないことでペナルティがありますか?

dispatch_async(dispatch_get_main_queue(), ^{
   // do work here
});
215
Egil

いいえ、すでにメインスレッドに参加しているかどうかを確認する必要はありません。ブロックをメインキューにディスパッチすることで、ブロックがメインスレッドでシリアルに実行されるようにスケジューリングします。これは、対応する実行ループが実行されるときに発生します。

すでにメインスレッドを使用している場合、動作は同じです。ブロックはスケジュールされ、メインスレッドの実行ループが実行されるときに実行されます。

141
user557219

上記の非同期ディスパッチの場合、メインスレッドにいるかどうかを確認する必要はありません。 Bavariousが示すように、これは単純にキューに入れられ、メインスレッドで実行されます。

ただし、dispatch_sync()を使用して上記を実行しようとして、コールバックがメインスレッド上にある場合、アプリケーションはその時点でデッドロックします。これを私の答え here で説明します。これは、-performSelectorOnMainThread:からコードを移動するときにこの動作に驚いたからです。そこで言及したように、ヘルパー関数を作成しました。

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

現在のメソッドがメインスレッド上にない場合は、メインスレッド上でブロックを同期的に実行します。メインスレッド上にある場合は、ブロックをインラインで実行します。これを使用するには、次のような構文を使用できます。

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});
94
Brad Larson

他の回答で述べたように、メインスレッドからのdispatch_asyncは問題ありません。

ただし、ユースケースによっては、デメリットを考慮する可能性のある副作用があります。ブロックはキューでスケジュールされるため、制御が実行ループに戻るまで実行されず、遅延の影響があります。ブロックの実行。

例えば、

NSLog(@"before dispatch async");
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"inside dispatch async block main thread from main thread");
});
NSLog(@"after dispatch async");

印刷されます:

before dispatch async
after dispatch async
inside dispatch async block main thread from main thread

このため、ブロックが外側のNSLogの中間で実行されることを期待している場合、dispatch_asyncは役に立ちません。

46
Michael Chinen

いいえ、メインスレッドにいるかどうかを確認する必要はありません。 Swiftでこれを行う方法は次のとおりです。

runThisInMainThread { () -> Void in
    runThisInMainThread { () -> Void in
        // No problem
    }
}

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

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

1
Esqarrouth