使用NWPathMonitor配合BehaviorSubject监控网络连通性出现重复触发问题
问题根因
- 最高频触发原因是
NetworkService单例实现错误:如果你的shared是计算属性而非静态存储属性,每次调用NetworkService.shared都会创建全新的NWPathMonitor实例,每个实例的回调都会独立触发事件,事件量会随实例数量增长快速堆积,最终导致应用崩溃。 - 其次是线程安全问题:你的
previousValue是普通存储属性,读写操作没有限定在同一队列,即使加了信号量也可能因为跨队列读写出现竞态,导致相等判断逻辑失效。 NWPathMonitor的pathUpdateHandler会在任意路径属性变化时触发,哪怕网络连通状态没有变化(比如WiFi切换到蜂窝网络、网络时延波动等),都会触发回调,如果没有过滤相同值,就会收到大量重复的连通状态事件。- 额外的代码问题:你的
pathUpdateHandler没有加[weak self]修饰,会造成循环引用,也可能引发异常的事件回调。
修复方案
1. 修正单例与监听逻辑
确保NetworkService全局唯一,所有状态读写都在NWPathMonitor的回调串行队列执行(天然线程安全,不需要额外加信号量):
import Network import RxSwift class NetworkService { // 静态存储属性,全局唯一实例 static let shared = NetworkService() private let monitor = NWPathMonitor() let connected = BehaviorSubject<Bool>(value: true) private var previousStatus: Bool = true // 私有初始化方法,禁止外部创建新实例 private init() { let queue = DispatchQueue(label: "com.yourapp.NetworkMonitor") monitor.pathUpdateHandler = { [weak self] path in guard let self = self else { return } let currentStatus = path.status == .satisfied // 状态无变化直接跳过,所有读写都在当前串行队列执行,无竞态问题 guard currentStatus != self.previousStatus else { return } self.previousStatus = currentStatus self.connected.onNext(currentStatus) } monitor.start(queue: queue) } }
2. 订阅侧增加重复值过滤(推荐)
即使上游出现异常重复事件,也可以通过Rx内置操作符在订阅侧兜底过滤,需要操作UI的话务必切换到主队列:
NetworkService.shared.connected .distinctUntilChanged() // 过滤连续相同的事件 .observe(on: MainScheduler.instance) // 涉及UI操作必须切到主队列 .subscribe(onNext: { connected in print("network connected: \(connected)") // 你的业务逻辑 }) .disposed(by: disposeBag)
3. 冗余逻辑清理
你之前添加的信号量逻辑可以完全删除,NWPathMonitor的回调会在你传入的串行队列中串行执行,不会出现并发调用的情况,额外加信号量只会增加不必要的性能损耗甚至死锁风险。
内容的提问来源于stack exchange,提问作者Vahid
相关产品推荐
相关产品推荐

