Reputation: 1939
I need an observer to keep my app updated on the connectivity status of the device.
NWPathMonitor
seems to be the standard approach. So I go like this:
class NetworkService {
let monitor = NWPathMonitor()
let connected = BehaviorSubject(value: true)
private init() {
monitor.pathUpdateHandler = { path in
let value = path.status == .satisfied
self.connected.onNext(value)
}
let queue = DispatchQueue(label: "NetworkMonitor")
monitor.start(queue: queue)
}
}
And this is where I subscribe to connected
NetworkService.shared.connected.subscribe(onNext: { connected in
print("network connected: \(connected)")
}).disposed(by: disposeBag)
As soon as the app starts, onNext
starts firing like crazy, flooding the console with network connected: true
until the app crashes.
I tried adding a local cache variable so the onNext
part fires only if there's been a change on the value.
if (value != self.previousValue) {
self.previousValue = value
self.connected.onNext(value)
}
Same happens still. So I guessed maybe the monitor is updating too frequently to allow the cache variable to get assigned, and I tried adding a semaphore ...
self.semaphore.wait()
if (value != self.previousValue) {
self.previousValue = value
self.connected.onNext(value)
}
self.semaphore.signal()
And event that didn't help. Still getting a flood of print messages and the app crashes.
BTW, if you were wondering this is how I declare the semaphore in my class:
let semaphore = DispatchSemaphore( value: 1)
Upvotes: 2
Views: 1145
Reputation: 33967
I'm not seeing the same behavior from the class as you, but a simple solution is to use .distinctUntilChanged()
which will stop an event from propagating unless it is different than the previous event.
If the above doesn't stop the flood of events, then the problem isn't with the code you have presented, but with something else you haven't told us about.
Also, I would have written it like this:
extension NWPathMonitor {
var rx_path: Observable<NWPath> {
Observable.create { [self] observer in
self.pathUpdateHandler = { path in
observer.onNext(path)
}
let queue = DispatchQueue(label: "NetworkMonitor")
self.start(queue: queue)
return Disposables.create {
self.cancel()
}
}
}
}
With the above, it's easy to access by doing:
let disposable = NWPathMonitor().rx_path
.map { $0.status == .satisfied }
.debug()
.subscribe()
The subscription will keep the NWPathMonitor object alive for the duration of the subscription. Calling dispose() on the disposable will shut down the subscription and release the NWPathMonitor object.
Upvotes: 1