66//
77
88import Foundation
9+ #if compiler(>=6.0)
10+ public import AsyncTimer
11+ #else
12+ @_exported import AsyncTimer
13+ #endif
914
1015// Enforce minimum Swift version for all platforms and build systems.
1116#if swift(<5.10)
@@ -16,7 +21,7 @@ import Network
1621
1722public enum NetworkPathMonitorInfo : Sendable {
1823 /// Current NetworkPathMonitor version.
19- public static let version = " 0.1.2 "
24+ public static let version = " 0.1.3 "
2025}
2126
2227/// A class that monitors network path changes using `NWPathMonitor`.
@@ -26,8 +31,8 @@ public actor NetworkPathMonitor {
2631 /// The queue on which the network path monitor runs.
2732 private let monitorQueue : DispatchQueue
2833
29- /// Debounce interval in seconds .
30- private let debounceInterval : Interval
34+ /// The debouncer to debounce network path updates .
35+ private let debouncer : AsyncDebouncer
3136
3237 /// The network path update handler.
3338 private var networkPathUpdater : PathUpdateHandler ?
@@ -38,9 +43,6 @@ public actor NetworkPathMonitor {
3843 /// A Boolean value that indicates whether the network path monitor is valid.
3944 public private( set) var isActive : Bool = false
4045
41- /// Task for debouncing path updates.
42- private var debounceTask : Task < Void , Never > ?
43-
4446 /// Current network path.
4547 public private( set) var currentPath : NetworkPath
4648
@@ -54,24 +56,20 @@ public actor NetworkPathMonitor {
5456 /// - Parameter queue: The queue on which the network path monitor runs. Default is a serial queue with a unique label.
5557 /// - Parameter debounceInterval: Debounce interval. If set to 0, no debounce will be applied. Default is 0 seconds.
5658 public init ( queue: DispatchQueue = . init( label: " com.networkPathMonitor. \( UUID ( ) ) " ) ,
57- debounceInterval: Interval = . seconds ( 0 ) )
59+ debounceInterval: Interval = . zero )
5860 {
59- precondition ( debounceInterval. nanoseconds >= 0 , " debounceInterval must be greater than or equal to 0 " )
61+ precondition ( debounceInterval. isValid , " debounceInterval must be greater than or equal to 0 " )
6062 monitorQueue = queue
6163 currentPath = NetworkPath ( nwPath: networkMonitor. currentPath)
6264 previousYieldPath = currentPath
63- self . debounceInterval = debounceInterval
65+ debouncer = AsyncDebouncer ( debounceTime : debounceInterval)
6466 networkMonitor. pathUpdateHandler = { [ weak self] path in
6567 guard let self else { return }
6668 Task { await self . handlePathUpdate ( path) }
6769 }
6870 }
6971
7072 deinit {
71- if let debounceTask {
72- debounceTask. cancel ( )
73- self . debounceTask = nil
74- }
7573 pathUpdateContinuation = nil
7674 networkPathUpdater = nil
7775 networkMonitor. pathUpdateHandler = nil
@@ -99,24 +97,10 @@ public actor NetworkPathMonitor {
9997 private func handlePathUpdate( _ path: NWPath ) async {
10098 // Before yielding, keep the previous sequence
10199 currentPath = NetworkPath ( nwPath: path, sequence: previousYieldPath. sequence)
102-
103- debounceTask? . cancel ( )
104- guard debounceInterval. nanoseconds > 0 else {
105- // No debounce, yield immediately
106- debounceTask = nil
100+ // Yield the path by debouncer
101+ await debouncer. call { [ weak self] in
102+ guard let self else { return }
107103 await yieldNetworkPath ( )
108- return
109- }
110- // Debounce is active
111- debounceTask = Task {
112- do {
113- try await Task . sleep ( nanoseconds: UInt64 ( self . debounceInterval. nanoseconds) )
114- await self . yieldNetworkPath ( )
115- } catch is CancellationError {
116- // Task was cancelled, do nothing
117- } catch {
118- print ( " Error during debounce sleep: \( error) " )
119- }
120104 }
121105 }
122106
@@ -182,30 +166,3 @@ public extension NetworkPathMonitor {
182166 networkPathUpdater = handler
183167 }
184168}
185-
186- // MARK: - Duration Convenience
187-
188- public extension NetworkPathMonitor {
189- enum Interval : Sendable {
190- case nanoseconds( _: Int )
191- case microseconds( _: Int )
192- case milliseconds( _: Int )
193- case seconds( _: Double )
194- case minutes( _: Int )
195-
196- var nanoseconds : Int {
197- switch self {
198- case let . nanoseconds( value) :
199- return value
200- case let . microseconds( value) :
201- return value * 1000
202- case let . milliseconds( value) :
203- return value * 1_000_000
204- case let . seconds( value) :
205- return Int ( value * 1_000_000_000 )
206- case let . minutes( value) :
207- return value * 60 * 1_000_000_000
208- }
209- }
210- }
211- }
0 commit comments