我有一个可能来自任何线程的回调。当我得到这个回调时,我想在主线程上执行某个任务。
我是否需要检查我是否已经在主线程上 - 或者在调用下面的代码之前不执行此检查是否有任何惩罚?
dispatch_async(dispatch_get_main_queue(), ^{
// do work here
});
不,您不需要检查您是否已经在主线程上。通过将块分派到主队列,您只是将块安排在主线程上串行执行,这发生在相应的运行循环运行时。
如果您已经在主线程上,则行为是相同的:该块被调度,并在主线程的运行循环运行时执行。
对于您上面描述的异步调度情况,您不需要检查您是否在主线程上。正如 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
});
dispatch_set_specific()
在您描述的情况下是否会有所帮助: stackoverflow.com/a/12806754/19679 。
正如提到的其他答案,来自主线程的 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 不会帮助您。
不,你不需要检查你是否在主线程中。以下是在 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
async
分派回主队列,它将运行,但可能会打乱您的操作的预期时间。例如viewDidLoad()
not running until after the view is first displayed 中的 UI 代码。