From d44e286b0ab2be870d9b43e6ef95a586230dcb1c Mon Sep 17 00:00:00 2001 From: Varun Santhanam Date: Sun, 31 Mar 2024 09:06:22 -0700 Subject: [PATCH] Throw cancellation errors when async observation is cancelled --- .../NetworkMonitor+Concurrency.swift | 31 ++++++++++++------- .../API/NetworkMonitor/NetworkMonitor.swift | 4 ++- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Sources/NetworkReachability/API/NetworkMonitor/NetworkMonitor+Concurrency.swift b/Sources/NetworkReachability/API/NetworkMonitor/NetworkMonitor+Concurrency.swift index 7b0616b7..fff0897a 100644 --- a/Sources/NetworkReachability/API/NetworkMonitor/NetworkMonitor+Concurrency.swift +++ b/Sources/NetworkReachability/API/NetworkMonitor/NetworkMonitor+Concurrency.swift @@ -31,16 +31,20 @@ public extension NetworkMonitor { /// Retrieve the latest known network path using [Swift Concurrency](https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html) /// /// ```swift - /// func updateReachability() async { - /// let path = await NetworkMonitor.networkPath + /// func updateReachability() async throws { + /// let path = try await NetworkMonitor.networkPath /// // Do something with `path` /// } /// ``` static var networkPath: NWPath { - get async { - await withUnsafeContinuation { continuation in + get async throws { + try await withUnsafeThrowingContinuation { continuation in NetworkMonitor.networkPath { path in - continuation.resume(returning: path) + if Task.isCancelled { + continuation.resume(throwing: CancellationError()) + } else { + continuation.resume(returning: path) + } } } } @@ -55,7 +59,7 @@ public extension NetworkMonitor { /// // Do something with `path` /// } /// ``` - static var networkPathUpdates: AsyncStream { + static var networkPathUpdates: AsyncThrowingStream { stream(.init()) } @@ -68,7 +72,7 @@ public extension NetworkMonitor { /// // Do something with `path` /// } /// ``` - static func networkPathUpdates(requiringInterfaceType interfaceType: NWInterface.InterfaceType) -> AsyncStream { + static func networkPathUpdates(requiringInterfaceType interfaceType: NWInterface.InterfaceType) -> AsyncThrowingStream { stream(.init(requiredInterfaceType: interfaceType)) } @@ -82,16 +86,21 @@ public extension NetworkMonitor { /// } /// ``` @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) - static func networkPathUpdates(prohibitingInterfaceTypes interfaceTypes: [NWInterface.InterfaceType]) -> AsyncStream { + static func networkPathUpdates(prohibitingInterfaceTypes interfaceTypes: [NWInterface.InterfaceType]) -> AsyncThrowingStream { stream(.init(prohibitedInterfaceTypes: interfaceTypes)) } } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -private func stream(_ monitor: NWPathMonitor) -> AsyncStream { - .init(bufferingPolicy: .bufferingNewest(1)) { continuation in +private func stream(_ monitor: NWPathMonitor) -> AsyncThrowingStream { + .init { continuation in monitor.pathUpdateHandler = { path in - continuation.yield(path) + if Task.isCancelled { + monitor.cancel() + continuation.finish(throwing: CancellationError()) + } else { + continuation.yield(path) + } } monitor.start(queue: .networkMonitorQueue) } diff --git a/Sources/NetworkReachability/API/NetworkMonitor/NetworkMonitor.swift b/Sources/NetworkReachability/API/NetworkMonitor/NetworkMonitor.swift index c9636667..ebf06351 100644 --- a/Sources/NetworkReachability/API/NetworkMonitor/NetworkMonitor.swift +++ b/Sources/NetworkReachability/API/NetworkMonitor/NetworkMonitor.swift @@ -346,7 +346,9 @@ public final class NetworkMonitor { } } else if #available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) { Task { - completionHandler(path) + await MainActor.run { + completionHandler(path) + } } } else { DispatchQueue.main.async {