我有一个可能来自任何线程的回调。当我得到这个回调时,我想在主线程上执行某个任务。
我是否需要检查我是否已经在主线程上 - 或者是否通过调用以下代码执行此检查而遭受任何惩罚?
dispatch_async(dispatch_get_main_queue(), ^{
// do work here
});
答案 0 :(得分:140)
不,你不需要检查你是否已经在主线程上。通过将块调度到主队列,您只需要调度要在主线程上串行执行的块,这在运行相应的运行循环时会发生。
如果您已经在主线程上,行为是相同的:块被调度,并在运行主线程的运行循环时执行。
答案 1 :(得分:94)
对于上面描述的异步调度案例,您不需要检查是否在主线程上。正如Bavarious所说,这将简单地排队等候在主线程上运行。
但是,如果您尝试使用dispatch_sync()
执行上述操作并且您的回调位于主线程上,那么您的应用程序将在此时死锁。我在回答here中对此进行了描述,因为从-performSelectorOnMainThread:
移动代码时,这种行为让我感到惊讶。正如我在那里提到的,我创建了一个辅助函数:
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
如果您所在的方法当前不在主线程上,它将在主线程上同步运行一个块,如果是,则只执行块内联。您可以使用以下语法来使用它:
runOnMainQueueWithoutDeadlocking(^{
//Do stuff
});
答案 2 :(得分:45)
正如其他提到的答案,主线程中的dispatch_async很好。
但是,根据您的使用情况,有一个副作用,您可能会认为是一个缺点:由于块是在队列上调度的,因此它将不会执行,直到控制返回到运行循环,这将具有延迟你的区块执行的效果。
例如,
NSLog(@"before dispatch async");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"inside dispatch async block main thread from main thread");
});
NSLog(@"after dispatch async");
将打印出来:
before dispatch async
after dispatch async
inside dispatch async block main thread from main thread
出于这个原因,如果您希望在外部NSLog之间执行该块,dispatch_async将无法帮助您。
答案 3 :(得分:1)
不,你不需要检查你是否在主线程中。以下是您在Swift中执行此操作的方法:
runThisInMainThread { () -> Void in
runThisInMainThread { () -> Void in
// No problem
}
}
func runThisInMainThread(block: dispatch_block_t) {
dispatch_async(dispatch_get_main_queue(), block)
}
它作为我的仓库中的标准功能包含在内,请查看:https://github.com/goktugyil/EZSwiftExtensions