iOS-DispatchQueue.main.asyncAfter(deadline:.now())和perform(_:with:afterDelay :)之间的延迟为0的差异

时间:2018-09-04 08:59:14

标签: ios objective-c swift grand-central-dispatch foundation

我意识到,当主队列“忙”时,使用DispatchQueue.main.asyncAfter(deadline: .now())perform(_:with:afterDelay:0)是有区别的。

请注意,在我的情况下,从主队列中调用了perform(_:with:afterDelay:)

好像DispatchQueue.main.asyncAfter(deadline: .now())在下一个运行循环中立即执行任务而无需关心主队列,但是{0}延迟为0的perform(_:with:afterDelay:)将等待并仅在主队列“空闲”时才执行任务(也许不会在下一个运行循环中调用。

根据perform(_:with:afterDelay:)的Apple文档

  

将延迟指定为0不一定会使选择器立即执行。选择器仍在线程的运行循环中排队,并尽快执行。

我不确定我是否正确理解它们,所以有人可以帮助我解释一下它们之间的区别是什么吗? 尽快执行是什么意思?

我发现了一个相同的问题here,但似乎不是我想要的。

1 个答案:

答案 0 :(得分:2)

我创建了这个独立的测试来探讨这个主题。

class ViewController: UIViewController {

    @objc func test1(_ info: Any) {
        guard let str = info as? String else { return }
        sleep(1)
        print(str)

        if str != "selector 3" {
            self.perform(#selector(test1), with: "selector 3", afterDelay: 0)
        }

        DispatchQueue.main.asyncAfter(deadline: .now()) {
            sleep(1)
            print("dispatch 4 queued by \(str)")
        }

    }


    @IBAction func test(_ sender: UIButton) {
        print("begin test")

        self.perform(#selector(test1), with: "selector 1", afterDelay: 0)

        DispatchQueue.main.asyncAfter(deadline: .now()) {
            DispatchQueue.main.asyncAfter(deadline: .now()) {
                sleep(1)
                print("dispatch 3")
            }
            sleep(1)
            print("dispatch 1")
        }

        self.perform(#selector(test1), with: "selector 2", afterDelay: 0)

        DispatchQueue.main.asyncAfter(deadline: .now()) {
            sleep(1)
            print("dispatch 2")
        }

        print("end test")
    }

}

结果输出:

begin test
end test
dispatch 1
dispatch 2
selector 1
selector 2
dispatch 3
dispatch 4 queued by selector 1
dispatch 4 queued by selector 2
selector 3
selector 3
dispatch 4 queued by selector 3
dispatch 4 queued by selector 3

要注意的事情:

  1. begin testend test在任何其他输出之前打印,表明perform(_:with:afterDelay:)DispatchQueue.main.asyncAfter都已排队并稍后运行。
  2. 前两个DispatchQueueperform之前运行,即使它们以不同的顺序排队。
  3. 所有打印间隔一秒,这意味着它们都在同一队列中运行,等待上一张打印完成。
  4. dispatch 3不会跳到selector 1selector 2的前面,即使它在dispatch 1打印之前已经排队。

结论:

  1. Dispatch.main.asyncAfterperform(_:with:afterDelay:)都将它们的选择器/关闭队列放入队列中,以便稍后执行。由于您正在主线程上运行perform(_:with:afterDelay:),因此它使用主队列进行调度。
  2. 出于某些未知的原因(在我看来),当在同一运行循环中排队时,Dispatch.main.asyncAfter(0)个调用在perform(_:with:afterDelay:0)个调用之前排队。注意:如果根本没有任何延迟添加到Dispatch.main.asyncAfter,则它将在perform(_:with:afterDelay:)之后排队。例如,尝试使用.now() + .milliseconds(1)
  3. 尽快执行只是表示它们已按队列顺序排队和处理的另一种方式。取决于任务在前面的队列中花费的时间,在最终处理任务之前,可能需要运行多次运行循环。