我有一个回调,它可能来自任何线程。当我得到这个回调时,我想在主线程上执行某个任务。

我需要检查我是否已经在主线程上-或者在调用下面的代码之前不执行这个检查有任何惩罚吗?

dispatch_async(dispatch_get_main_queue(), ^{
   // do work here
});

不,您不需要检查您是否已经在主线程上。通过将块调度到主队列,您只是将块调度到主线程上串行执行,这在相应的运行循环运行时发生。

如果你已经在主线程上,行为是相同的:块被调度,并在主线程的运行循环运行时执行。


对于上面描述的异步分派情况,您不需要检查是否在主线程上。正如Bavarious所指出的,这将简单地排队在主线程上运行。

但是,如果您尝试使用dispatch_sync()来执行上述操作,并且您的回调是在主线程上,那么您的应用程序将在此时死锁。我在这里的回答中描述了这一点,因为当从-performSelectorOnMainThread:移动一些代码时,这种行为让我感到惊讶。正如我在那里提到的,我创建了一个helper函数:

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

如果你所在的方法当前不在主线程上,它会在主线程上同步运行一个块,如果在主线程上,它会内联执行块。你可以使用如下语法来使用这个:

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});

正如其他答案所提到的,来自主线程的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