29

Kiwiテストフレームワークを使用して、アプリの認証方法をテストしています。次のようなdispatch_syncの呼び出しで、テストがフリーズします。

dispatch_queue_t main = dispatch_get_main_queue();
dispatch_sync(main, ^
                  {
                      [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret];
                  });

誰かが何かヒントがあれば、なぜそこでフリーズするのか知りたいです。

4

2 に答える 2

57

フリーズのヒントに関する質問の2番目の部分については、次のようにします。

dispatch_syncキューを呼び出すときは、このキューが現在のキュー( )ではないことを常に確認してdispatch_get_current_queue()ください。なぜならdispatch_sync、最初のパラメータとして渡されたキューにブロックをキューに入れ、次にこのブロックが実行されるのを待ってから続行するからです。

したがってdispatch_get_current_queue()、ブロックをエンキューするキューとが同じである場合、つまりメインキューの場合、メインキューはdispatch_syncの呼び出しでブロックされ、メインキューがブロックを実行するまでブロックされますが、できません。キューがブロックされ、ここに美しいデッドロックが発生します

1つの解決策(iOS6までの[編集]):

dispatch_queue_t main = dispatch_get_main_queue();
dispatch_block_t block = ^
              {
                  [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret];
              };
if (dispatch_get_current_queue() == main)
  block(); // execute the block directly, as main is already the current active queue
else
  dispatch_sync(main, block); // ask the main queue, which is not the current queue, to execute the block, and wait for it to be executed before continuing

[編集]注意してくださいdispatch_get_current_queue()。デバッグ目的でのみ使用され、本番環境では使用されません。実際、dispatch_get_current_queueiOS6.1.3以降は非推奨になっています。

メインキュー(メインスレッドのみに関連付けられている)の特定のケースにいる場合は、代わりに[NSThread isMainThread]@meaning-mattersで提案されているようにテストできます。


ちなみに、あなたdispatch_syncはあなたの場合にそうする必要がありますか?通知を少し後で送信し、送信されるまでブロックしないようにすることは、あなたのケースでは許容できると思います。したがって、dispatch_async(キュー比較条件を使用して必要とする代わりに)を使用することも検討dispatch_syncできます。これにより、デッドロックの問題も回避できます。

于 2012-09-11T23:13:31.027 に答える
42

dispatch_get_current_queue()iOS 6以降は非推奨であり、iOS6.1.3のメインスレッドにdispatch_get_current_queue() == dispatch_get_main_queue()あることが判明しました。false

iOS 6以降では、次のようにします。

dispatch_block_t block = ^
{
    <your code here>
};

if ([NSThread isMainThread])
{
    block();
}
else
{
    dispatch_sync(dispatch_get_main_queue(), block);
}
于 2013-03-28T21:49:43.460 に答える