首页 > 解决方案 > iOS RunLoop 和 DispatchQueue.main.async

问题描述

为什么print("2")在下面的代码中永远不会调用该部分?我认为内部main.async会将块推送到主循环的队列中,然后RunLoop.run执行它,但显然不是这样。(它打印1, run, run,run等)

此外,如果我删除了外层main.async,直接运行该块中的代码(仍在主队列中,在viewDidLoad新的单视图应用程序中),那么内层main.async块确实会被执行(打印1、、、run2。为什么这种变化会产生如此大的影响?

var x = -1
DispatchQueue.main.async {   //  comment out this line for question #2
    print("1")
    x = 1
    DispatchQueue.main.async {
        print("2")
        x = 2
    }
    while x == 1 {
        print("run")
        RunLoop.main.run(mode: .default, before: Date() + 1)
    }
}   //  comment out this line for question #2

标签: iosnsrunloopdispatch-queue

解决方案


在您的第一个示例中,第一个async阻塞main串行队列,直到它从该外部调用返回,这在isasync时不会发生。该内部 GCD任务(更新到)将永远没有机会运行,因为该串行 GCD 队列现在在该循环中被阻塞。在主运行循环上的尝试不会规避 GCD 串行队列的规则/行为。它只会耗尽已添加到其中的事件的运行循环。x1asyncx2whilerun

在您的第二个示例中,您没有阻止 GCDmain队列,因此当您点击 时,更新到run的已调度块确实有机会运行,让它继续。x2

最重要的是,不要将 GCD 主队列和主运行循环混为一谈。是的,它们都使用主线程,但不能使用运行循环来规避串行 GCD 队列的行为。


推荐阅读