如何在没有死锁的情况下同步调度主队列?

zou*_*oul 62 objective-c grand-central-dispatch ios objective-c-blocks

我需要同步在主队列上调度一个块.我不知道我目前是在主线程上运行还是不运行.天真的解决方案看起来像这样:

dispatch_sync(dispatch_get_main_queue(), block);
Run Code Online (Sandbox Code Playgroud)

但是如果我当前在主队列上运行的块中,则此调用会产生死锁.(同步调度等待块完成,但块甚至没有开始运行,因为我们正在等待当前块完成.)

显而易见的下一步是检查当前队列:

if (dispatch_get_current_queue() == dispatch_get_main_queue()) {
    block();
} else {
    dispatch_sync(dispatch_get_main_queue(), block);
}
Run Code Online (Sandbox Code Playgroud)

这有效,但很难看.在我至少将它隐藏在一些自定义功能之前,是不是有更好的解决方案来解决这个问题?我强调我不能异步调度块 - 应用程序处于异步调度块将"执行得太晚"的情况.

Bra*_*son 70

我需要在我的Mac和iOS应用程序中经常使用这样的东西,所以我使用以下帮助函数(最初在本回答中描述):

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}
Run Code Online (Sandbox Code Playgroud)

你打电话通过

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});
Run Code Online (Sandbox Code Playgroud)

这几乎就是你在上面描述的过程,我和其他一些开发人员进行了交谈,他们为自己独立制作了类似的东西.

我使用[NSThread isMainThread]而不是检查dispatch_get_current_queue(),因为该函数警告部分曾警告不要使用它进行身份测试,并且该调用在iOS 6中已弃用.

  • @pnizzle - 是的,有很多情况会发生这种情况.如果你有哪些操作执行,必须在主线程上运行,又被称为从许多地方的常用方法,一些在主线程上,有些没有,这样的功能是非常有用的.我写这个是因为我自己需要多个地方. (3认同)