swift 为什么DispatchQueue.main.async可以用作RunLoop.current.run?的输入源

mnemlml8  于 2023-08-02  发布在  Swift
关注(0)|答案(2)|浏览(149)
import Dispatch
import Foundation

DispatchQueue.main.async {
    print("just print in main async")
}

RunLoop.current.run(mode: .default, before: .distantFuture)

print("RunLoop.current.run ends!")

字符串


的数据
如果runLoop在打印“just print inmain async”后结束,是否意味着runLoop被main.async终止(就像UI事件一样)?
我想知道这个案子到底发生了什么。

798qvoo8

798qvoo81#

你问:
为什么DispatchQueue.main.async可以用作RunLoop.current.run的输入源?
你描述的行为并不一定意味着DispatchQueue.main.async {…}在技术上是runloop的“输入源”。它只意味着run(mode:before:)可以允许libDispatch在返回之前运行已调度的项。我们无法获得这些实施细节。
如果runLoop在打印“just print in main async”后结束,是否[意味着runloop]被main.async终止(就像UI事件一样)?
不一定。以下是一些观察结果:

  • 不是为了吹毛求疵,但当您从run(before:mode:)返回时,它不会“终止”,而是它只运行一次循环。这只是一个在返回之前是否运行调度的块的问题。
  • 我在macOS和iOS目标中看到了略有不同的行为,以及我在哪里这样做(以及我是在@IBAction还是viewDidLoad中这样做的)。这使得我更加不愿意对实现细节做出实质性的假设。
  • 我看到了种族行为。请考虑以下情况(其中我将print替换为“兴趣点”路标):
import UIKit
import os.log

let poi = OSLog(subsystem: "Test", category: .pointsOfInterest)

class ViewController: UIViewController {
    @IBAction func didTapButton(_ sender: Any) {
        for i in 0 ..< 10 {
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                print("after")
                os_signpost(.event, log: poi, name: "After 1 sec", "%d", i)
            }
        }

        for i in 0 ..< 10 {
            DispatchQueue.main.async {
                print("immediate", i)
                os_signpost(.event, log: poi, name: "Immediate", "%d", i)
            }
        }

        RunLoop.current.run(mode: .default, before: .distantFuture)

        os_signpost(.event, log: poi, name: "Run")
    }
}

字符串
有时候我得到了:
x1c 0d1x的数据
其他时候我得到:



无可否认,前一种行为很难再现。但种族往往很难显现。
我的底线是,我会犹豫是否将“runloop输入源”一词与调度到队列的项目一起使用(没有看到RunLoop源代码或苹果的一些正式保证)。GCD和runloops是非常不同的技术堆栈/模式。我们通常会使用GCD(或者Swift并发或者其他类似的东西)来代替runloop模式。此外,我会犹豫是否依赖RunLoop.current.run来从调度队列中排出排队的项目。
GCD在很大程度上消除了对传统运行循环run(反)模式的需要。如果这个问题纯粹是出于好奇,那么希望上面的内容能提供一些有用的观察结果。但是,如果引入runloop是为了在GCD中实现某些功能行为,我可能建议就这个更广泛的问题单独提出一个问题,并避免在混合中引入RunLoop

gc0ot86w

gc0ot86w2#

是的,我认为在提供的代码中,由于DispatchQueue.main.async块,运行循环将在打印“just print in main async”后结束。
As run循环将简单地无限期地等待事件(直到事件发生,因为您提供了.distantFuture)。
在某个时刻,会发生事件,该事件可以是用户交互事件(UI事件)或正在处理的另一个源。此事件将中断运行循环,并允许调度的DispatchQueue.main.async块在主队列上执行。
然后将从异步执行的块中打印“just print in main async”。
然而,在打印的语句之后,没有更多的事件被安排,因此run循环最终将退出并打印“RunLoop.current.run ends!”。
希望这个链接也有帮助。

相关问题