Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use NWPathMonitor with Swift Modern Concurrency (AsyncStream) vs GCD (DispatchQueue)

I have noticed that the start(queue:) method in NWPathMonitor requires a queue of type DispatchQueue. Is there a way to implement this using Swift Modern Concurrency, probably using AsyncStream?

Using Apple documentation for AsyncStream, I have created the extension to NWPathMonitor, but I cannot start the NWPathMonitor monitor, any suggestion will be appreciated, thanks

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: )
    }
  }
}

Read Apple's documentation

like image 448
logicito Avatar asked Apr 17 '26 15:04

logicito


1 Answers

In iOS 17, macOS 14, etc., and later, NWPathMonitor conforms to AsyncSequence:

func startMonitoring() async {
    let monitor = NWPathMonitor()
    for await path in monitor {
        print(path.debugDescription)
    }
}

In earlier OS versions, you can wrap it in an AsyncStream and supply it a queue.

So:

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"))
        }
    }
}

Then you can do things like:

func startMonitoring() async {
    let monitor = NWPathMonitor()
    for await path in monitor.paths() {
        print(path.debugDescription)
    }
}

A few unrelated and stylistic recommendations, which I integrated in the above:

  1. I did not make this static, as we generally want our extensions to be as flexible as possible. If this is in an extension, we want the application developer to create whatever NWPathMonitor they want (e.g., perhaps requiring or prohibiting certain interfaces) and then create the asynchronous sequence for the updates for whatever path monitor they want.

  2. I made this a function, rather than a computed property, so that it is intuitive to an application developer that this will create a new sequence every time you call it. I would advise against hiding factories behind computed properties.

    The concern with a computed property is that it is not at all obvious to an application developer unfamiliar with the underlying implementation that if you access the same property twice that you will get two completely different objects. Using a method makes this a little more explicit.

Obviously, you are free to do whatever you want regarding these two observations, but I at least wanted to explain my rationale for the adjustments in the above code.

like image 171
Rob Avatar answered Apr 21 '26 00:04

Rob



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!