GCD在主线程中执行任务

时间:2011-04-14 11:14:07

标签: objective-c grand-central-dispatch

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

我是否需要检查我是否已经在主线程上 - 或者是否通过调用以下代码执行此检查而遭受任何惩罚?

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

4 个答案:

答案 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)

正如其他提到的答案,主线程中的di​​spatch_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