IOS - DispatchQueue.main.asyncAfter(deadline: .now()) 和 perform(_:with:afterDelay:) 之间的区别,延迟为 0

IOS - Difference between DispatchQueue.main.asyncAfter(deadline: .now()) and perform(_:with:afterDelay:) with 0 delay

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

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

似乎 DispatchQueue.main.asyncAfter(deadline: .now()) 在下一个 运行 循环中立即执行任务而不关心主队列但是 perform(_:with:afterDelay:) 0 延迟将等待并仅在主队列是时执行任务"free"(也许在下一个运行循环中不会被调用)。

根据 perform(_:with:afterDelay:)

的 Apple 文档

Specifying a delay of 0 does not necessarily cause the selector to be performed immediately. The selector is still queued on the thread’s run loop and performed as soon as possible.

我不确定我是否理解正确,所以谁能帮我解释一下它们之间到底有什么区别? 尽快执行 是什么意思?

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

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

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. 前两个 DispatchQueues 运行 在 performs 之前,即使它们以不同的顺序排队。
  3. 所有打印相隔一秒,这意味着它们都在同一个队列中 运行 等待前一个完成。
  4. dispatch 3 不会跳到 selector 1selector 2 之前,即使它在 dispatch 1 打印之前排队。

结论:

  1. Dispatch.main.asyncAfterperform(_:with:afterDelay:) 都将它们的 selector/closure 排队等待稍后执行。由于您在主线程上 运行ning perform(_:with:afterDelay:),它使用主队列进行调度。
  2. 由于某些(对我来说)未知的原因,当在同一个 运行 循环中排队时,Dispatch.main.asyncAfter(0) 个调用在 perform(_:with:afterDelay:0) 个调用之前排队。注意:如果在 Dispatch.main.asyncAfter 中添加任何延迟,它将在 perform(_:with:afterDelay:) 之后排队。例如,尝试使用 .now() + .milliseconds(1)
  3. 尽快执行 只是表示它们按队列顺序排队和处理的另一种说法。根据任务在前面队列中花费的时间,可能需要 运行 循环的许多 运行 才能最终处理任务。