将 NWPathMonitor 与 Swift 现代并发 (AsyncStream) 与 GCD (DispatchQueue) 结合使用

log*_*ito 3 concurrency swift nwpathmonitor asyncstream

我注意到start(queue:)中的方法NWPathMonitor需要类型为 的队列DispatchQueue。有没有办法使用 Swift 现代并发来实现这一点,可能使用AsyncStream

使用Apple文档AsyncStream,我已经创建了扩展NWPathMonitor,但我无法启动NWPathMonitor显示器,任何建议将不胜感激,谢谢

extension NWPathMonitor {
  static var nwpath: AsyncStream<NWPath> {
    AsyncStream { continuation in
      let monitor = NWPathMonitor()
      monitor.pathUpdateHandler = { path in
        continuation.yield(path)
      }
      continuation.onTermination = { @Sendable _ in
        monitor.cancel()
      }
      // monitor.start(queue: )
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

阅读苹果的文档

Rob*_*Rob 8

如果您将旧版 API 包装在某种延续模式中(无论是使用AsyncStreamwithCheckedContinuation或其他),则包装的代码将必须采用旧版 API 所需的任何模式。

因此,简而言之,如果由 an 包装的 APIAsyncStream需要调度队列,那么只需为其提供一个队列即可。

所以:

extension NWPathMonitor {
    func paths() -> AsyncStream<NWPath> {
        AsyncStream { continuation in
            pathUpdateHandler = { path in
                continuation.yield(path)
            }
            continuation.onTermination = { [weak self] _ in
                self?.cancel()
            }
            start(queue: DispatchQueue(label: "NSPathMonitor.paths"))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以做这样的事情:

func startMonitoring() async {
    let monitor = NWPathMonitor()
    for await path in monitor.paths() {
        print(path.debugDescription)
    }
}
Run Code Online (Sandbox Code Playgroud)

我在上面整合了一些不相关的和风格上的建议:

  1. 我没有这样做static,因为我们通常希望我们的扩展尽可能灵活。如果这是在扩展中,我们希望应用程序开发人员创建NWPathMonitor他们想要的任何内容(例如,可能需要或禁止某些接口),然后为他们想要的任何路径监视器创建更新的异步序列。

  2. 我将其设为函数,而不是计算属性,以便应用程序开发人员直观地知道每次调用它时都会创建一个新序列。我建议不要将工厂隐藏在计算属性后面。

    对计算属性的关注是,对于不熟悉底层实现的应用程序开发人员来说,如果访问同一属性两次,您将获得两个完全不同的对象,这一点并不明显。使用方法可以使这一点更加明确。

显然,对于这两个观察结果,您可以自由地做任何您想做的事情,但我至少想解释一下我在上述代码中进行调整的理由。