Reputation: 225
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
Upvotes: 7
Views: 1953
Reputation: 437552
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:
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.
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.
Upvotes: 14
Reputation: 30575
NWPathMonitor
already is an async sequence, use like this:
.task {
let monitor = NWPathMonitor()
for await path in monitor {
// path is NWPath struct
print("Status \(path.status)")
}
}
Upvotes: 0