59

ブロックをメインキューに同期してディスパッチする必要があります。私は現在メインスレッドかノーで実行しているかわかりません。純粋な解決策は次のようになります。デッドロックなしでメインキューに同期してディスパッチする方法はありますか?

dispatch_sync(dispatch_get_main_queue(), block); 

私が現在メインキューで実行中のブロック内にある場合、この呼び出しはデッドロックを作成します。 (同期ディスパッチは、ブロックが終了するのを待っていますが、現在のブロックが完了するのを待っているためブロックが実行を開始しません)。

明らかに次のステップは、現在のキューを確認することです。
if (dispatch_get_current_queue() == dispatch_get_main_queue()) { 
    block(); 
} else { 
    dispatch_sync(dispatch_get_main_queue(), block); 
} 

これは機能しますが、醜いです。私は少なくともいくつかのカスタム関数の背後にそれを隠す前に、この問題の良い解決策はありませんか?ブロックを非同期でディスパッチする余裕がないことを強調します。アプリは、非同期的にディスパッチされたブロックが「遅すぎる」実行される状況にあります。

+0

私はそれはかなり良い解決策だと思います。あなたが行うことができるのは、あらかじめ定義されたマクロとして作成することです。そのため、コードはあまりにも醜く見えません。 –

+1

これは多かれ少なかれ「テキストブック」の解決策です。 –

答えて

63

は、私は私のMacとiOSアプリケーション内でかなり定期的にこのようなものを使用する必要があるので、私は(もともとthis answerで説明)以下のヘルパー関数を使用します。あなたは

runOnMainQueueWithoutDeadlocking(^{ 
    //Do stuff 
}); 
経由で呼び出す

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

これは、あなたが上で説明したプロセスとほぼ同じです。私は、自分のためにこのようなものを独自に作り出したいくつかの他の開発者と話しました。

caveats section for that functionはかつて同一性試験とthe call was deprecated in iOS 6のためにこれを使用しないことを警告したので、私は、[NSThread isMainThread]代わりのdispatch_get_current_queue()を確認するを使用していました。

+0

また、 'dispatch_get_current_queue()'も廃止されました。 – txulu

+1

@Brad_Larsonは、コードを管理する開発者がメインスレッドから分岐しているかどうかわからない真の状況がありますか?私の信念は、コードがどのように動作しているかを知っていれば、メインスレッドやそれ以外のものが何であるかを知ることです。 – pnizzle

+2

@pnizzle - はい、これが発生するケースはたくさんあります。メインスレッド上で実行されなければならない操作が実行される共通の方法がある場合は、メインスレッド上のいくつかのスレッドから呼び出されますが、このような関数は非常に便利です。私は自分で複数の場所でそれが必要だったので、これを書いた。 –

0

最近UIの更新中にデッドロックが発生し始めました。それは私にこの回答を受け入れるrunOnMainQueueWithoutDeadlocking型のヘルパー関数を実装する私につながるこのスタックオーバーフローの質問をもたらします。

実際の問題は、ブロックからUIを更新するときに、dispatch_asyncではなくdispatch_syncを誤って使用して、UI更新のメインキューを取得するということです。コード補完を行うのは簡単ですし、事実の後には気づくのが難しいかもしれません。

ので、他の人がこの質問を読むため:同期実行は単にあなたが断続的に打つかもしれデッドロックを回避しますdispatch_**a**syncを使用して、を必要とされていない場合。メインキュー上またはメインスレッドでの同期のために

1

(それは同じではありません)私が使用:

import Foundation 

private let mainQueueKey = UnsafeMutablePointer<Void>.alloc(1) 
private let mainQueueValue = UnsafeMutablePointer<Void>.alloc(1) 


public func dispatch_sync_on_main_queue(block:() -> Void) 
{ 
    struct dispatchonce { static var token : dispatch_once_t = 0 } 
    dispatch_once(&dispatchonce.token, 
    { 
     dispatch_queue_set_specific(dispatch_get_main_queue(), mainQueueKey, mainQueueValue, nil) 
    }) 

    if dispatch_get_specific(mainQueueKey) == mainQueueValue 
    { 
     block() 
    } 
    else 
    { 
     dispatch_sync(dispatch_get_main_queue(),block) 
    } 
} 

extension NSThread 
{ 
    public class func runBlockOnMainThread(block:() -> Void) 
    { 
     if NSThread.isMainThread() 
     { 
      block() 
     } 
     else 
     { 
      dispatch_sync(dispatch_get_main_queue(),block) 
     } 
    } 

    public class func runBlockOnMainQueue(block:() -> Void) 
    { 
     dispatch_sync_on_main_queue(block) 
    } 
} 
関連する問題