主队列上异步任务的执行顺序

Leg*_*tik 1 grand-central-dispatch ios swift

在下面的代码中,print语句按它们包含的数字的顺序执行(1,2,3等)

override func viewDidLoad() {
    super.viewDidLoad()

    DispatchQueue.main.async {
        print("4")
    }

    print("1")
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    DispatchQueue.main.async {
        print("5")
    }

    print("2")
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    DispatchQueue.main.async {
        print("6")
    }

    print("3")
}
Run Code Online (Sandbox Code Playgroud)

你能解释为什么执行过程会这样发生吗?是viewWillAppearviewWillAppear方法已经在队列中,当我们派遣异步块中viewDidLoad

mat*_*att 9

viewWillAppearviewDidAppear方法已经在队列中,当我们派遣异步块中viewDidLoad

实际上:是的.它们并非"在队列中",但它们已经在列车中作为现有主队列代码序列的一部分.

这完全取决于runloop何时结束.在发生这种情况之前,异步调度到主队列的代码无法运行.实际上,我们必须完全结束这次CATransaction(runloop的一次"革命")之前print 4等等.

您可能已将此日志记录放入根视图控制器中.这是一种特殊情况,因为您的应用程序刚刚启动,在调用makeKeyAndVisible发送到窗口之前没有任何反应.

在那一刻viewDidLoad被召唤并被viewWillAppear连续称为这一召唤的一部分makeKeyAndVisible.

在此输入图像描述

在此输入图像描述

因此,相同的代码仍然在主线程上运行; 您的调度代码没有时间运行.这样我们就得到print 1print 2别的之前.

情况viewDidAppear有点不同:

在此输入图像描述

正如您所看到的,我们不再接受这种呼吁了makeKeyAndVisible.但主线程仍在运行,因为我们立即转向任何事务完成块(cleanUpAfterCAFlushAndRunDeferredBlocks).它可能有助于将其viewDidAppear视为有效的动画完成块viewWillAppear.这已经被配置为调用的一部分viewWillAppear,因此它仍然是同一事务的一部分.因此,viewDidAppearviewWillAppear没有停顿的情况下仍然可以实现print 3.

现在,在长期持续的启动顺序结束,你的主队列异步代码有机会运行,这确实在它被排队的顺序(print 4,print 5,print 6).