【问题标题】:IOS - Difference between DispatchQueue.main.asyncAfter(deadline: .now()) and perform(_:with:afterDelay:) with 0 delayIOS - DispatchQueue.main.asyncAfter(deadline: .now()) 和 perform(_:with:afterDelay:) 之间的区别,延迟为 0
【发布时间】:2018-09-04 08:59:13
【问题描述】:

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

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

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

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

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

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

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

【问题讨论】:

  • 猜测:main.asyncAfter 在主线程上运行,而 perform 方法在 NSObject 下,根据文档它在当前线程上执行(并不意味着主线程,它可以是你已经初始化的任何线程NSObject)。可能是您想在其他线程中延迟一段时间后执行一些操作。但是,如果您想确保要在主线程上运行,那么还有另一种方法 performSelector(onMainThread:with:waitUntilDone:modes:) 但它不提供延迟
  • @SahilManchanda 感谢您的建议并指出有关在主队列上调用perform(_:with:afterDelay:) 的问题。我忘了在问题中提到它。我已更新我的问题以使其更清楚。

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


【解决方案1】:

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

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:) 都将它们的选择器/闭包排队等待稍后执行。由于您在主线程上运行 perform(_:with:afterDelay:),因此它使用主队列进行调度。
  2. 由于某些未知(对我而言)原因,当在同一运行循环中排队时,Dispatch.main.asyncAfter(0) 呼叫在 perform(_:with:afterDelay:0) 呼叫之前排队。注意:如果有任何延迟被添加到Dispatch.main.asyncAfter,它将在perform(_:with:afterDelay:) 之后排队。例如,尝试使用.now() + .milliseconds(1)
  3. 尽快执行只是表示它们已排队并按队列顺序处理的另一种方式。根据任务在队列中占用多长时间,最终处理任务之前可能需要多次运行运行循环。

【讨论】:

  • 您还需要从其他线程执行一些测试才能获得合理的结果。
  • @dvp.petrov 为什么? OP 询问从主线程调用时的差异。
  • @vacawama 谢谢你的好例子。它完全解释了我在说什么。你对以上这4件事有什么结论吗?
  • @trungduc,我补充了一些结论。
猜你喜欢
  • 2017-04-01
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 1970-01-01
  • 2012-04-04
  • 2013-05-03
  • 2012-04-14
  • 2014-07-31
相关资源
最近更新 更多