使用NWPathMonitor监测网络时恢复连接回调两次的问题排查
问题原因与解决方案
这不是你的代码操作有误,而是NWPathMonitor的正常行为——网络恢复时,系统可能会多次触发路径更新回调:比如先通知路径已变为可用状态,再通知具体的网络接口类型(比如刚恢复时先识别到基础连接,再补全接口细节)。你的代码每次回调都发送通知,自然会收到两次触发。
解决核心是只在连接状态或关键属性发生实际变化时才发送通知,而非每次回调都执行。另外你的代码还漏了正确更新isConnected状态,这也是需要补全的细节。
修改后的代码
final class NetworkMonitor { static let shared = NetworkMonitor() private let queue = DispatchQueue.global(qos: .background) private let monitor: NWPathMonitor private(set) var isConnected = false private(set) var isExpensive = false private(set) var currentConnectionType: NWInterface.InterfaceType? private init() { monitor = NWPathMonitor() } func startMonitoring() { monitor.pathUpdateHandler = { [weak self] path in guard let self = self else { return } // 计算当前最新的状态值 let newIsConnected = path.status == .satisfied let newIsExpensive = path.isExpensive let newConnectionType = NWInterface.InterfaceType.allCases.first { path.usesInterfaceType($0) } // 只有当状态发生变化时,才更新属性并发送通知 let shouldNotify = newIsConnected != self.isConnected || newIsExpensive != self.isExpensive || newConnectionType != self.currentConnectionType guard shouldNotify else { return } // 更新属性 self.isConnected = newIsConnected self.isExpensive = newIsExpensive self.currentConnectionType = newConnectionType // 发送通知 NotificationCenter.default.post(name: .connectivityStatus, object: nil) } monitor.start(queue: queue) } func stopMonitoring() { monitor.cancel() } }
关键改动说明
- 补全连接状态判断:新增
newIsConnected变量,用path.status == .satisfied来准确判断设备是否真正处于联网状态(之前的代码完全未更新isConnected属性,属于疏漏)。 - 过滤重复通知:对比新状态与旧状态,只有当连接状态、网络成本、连接类型任意一项发生变化时,才执行属性更新和通知发送,避免无意义的重复触发。
- 优化接口类型获取:将
filter改为first,逻辑一致但性能更优。
额外补充:NWPathMonitor的回调触发时机不止是连接/断开,当网络路径的其他属性变化时(比如从Wi-Fi切换到蜂窝、网络从受限变为完全可用)也会触发,所以过滤重复通知是这类监控工具的常规操作。
内容的提问来源于stack exchange,提问作者Jayachandra A
相关产品推荐
相关产品推荐

