Kiwiテストフレームワークを使用して、アプリの認証方法をテストしています。次のようなdispatch_syncの呼び出しで、テストがフリーズします。
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_sync(main, ^
{
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret];
});
誰かヒントがあれば、なぜそこでフリーズするのか知りたいのですが。
フリーズのヒントに関する質問の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_queue
_はiOS6.1.3以降非推奨になっています。
メインキュー(メインスレッドのみに関連付けられている)の特定のケースにいる場合は、代わりに@ meaning-mattersで提案されているように_[NSThread isMainThread]
_をテストできます。
ちなみに、あなたの場合は_dispatch_sync
_する必要がありますか?通知を送信するのは少し後で、送信されるまでブロックしないことは許容できると思います。そのため、(_dispatch_async
_を使用してキュー比較条件を必要とする代わりに、_dispatch_sync
_を使用することも検討してください。 )、デッドロックの問題も回避できます。
dispatch_get_current_queue()
はiOS6以降非推奨になり、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);
}