我需要派遣块上的主队列,同步进行。 我不知道我目前的主线程或没有上运行。 天真的解决方案如下:
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);
}
这工作,但它的丑陋。 之前,我至少后面躲起来,一些自定义的功能,是不是有这个问题更好的解决办法? 我强调,我买不起异步分派块 - 应用程序是在将异步分派块将得到执行“为时已晚”的情况。
我需要我的Mac和iOS应用中相当经常使用这样的事情,所以我用下面的辅助函数(最初在描述这个答案 ):
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
你通过调用
runOnMainQueueWithoutDeadlocking(^{
//Do stuff
});
这是一个很值得你在上面描述的过程中,我已经说过了谁已经独立制作像这样为自己其他几个开发商。
我用[NSThread isMainThread]
而不是检查dispatch_get_current_queue()
因为该功能警告部警告一次对使用该身份检测和呼叫是在IOS 6弃用 。
对于同步在主队列或主线程(也就是不一样的),我使用:
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)
}
}
我最近开始在UI更新遇到了僵局。 这导致我这个堆栈溢出问题,这导致了我实现runOnMainQueueWithoutDeadlocking
基于公认的答案型的辅助功能。
真正的问题,虽然是从块更新UI时,我曾误用dispatch_sync
而不是dispatch_async
以获取UI更新主队列。 容易做到代码完成,或许很难在事后通知。
因此,为他人阅读这样一个问题: 如果不需要同步执行 ,只需使用dispatch_**a**sync
将避免你可能会间歇性地击中了僵局。