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

关于冻结提示的问题的第二部分:

dispatch_sync在队列上调用时,请始终验证此队列不是当前队列( dispatch_get_current_queue())。因为dispatch_sync会将您的块放在作为第一个参数传递的队列中,然后将等待该块执行后再继续

因此,如果dispatch_get_current_queue()您将块入队的队列相同,即在您的情况下是主队列,则主队列将阻塞对 dispatch_sync 的调用,直到......主队列执行了该块,但它不能,由于队列被阻塞,你在这里有一个漂亮的死锁

一种解决方案([编辑] 直到 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 起已被弃用。

如果您处于主队列的特定情况(仅与主线程相关联),您可以[NSThread isMainThread]按照@meaning-matters 的建议进行测试。


顺便说一句,你确定你需要dispatch_sync吗?我想稍后发送你的通知,避免阻塞直到它被发送,在你的情况下是可以接受的,所以你也可以考虑使用dispatch_async(而不是使用dispatch_sync和需要队列比较条件),这也可以避免死锁问题。

于 2012-09-11T23:13:31.027 回答
42

dispatch_get_current_queue()从 iOS 6 开始不推荐使用,并且dispatch_get_current_queue() == dispatch_get_main_queue()被发现false在 iOS 6.1.3 的主线程上。

在 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 回答