I was trying to implement Network connectivity using Network framework which apple offers us to handle network issues.
What I did was: 1.Whenever app gets in active state - I start monitoring network 2.Whenever app gets in background - I cancelled out monitoring to make low battery impact
The problem I encountered from this whenever I just go to background and comes back again to app it does not monitor again as we can't assign monitor instance again. We need to create new monitor instance to start monitoring again
I'm trying to reduce redundancy code as much as I can
So to achieve all the edgecases
Below is my approach:-
Network Monitor File
import Foundation
import Network
final class NetworkMonitor {
private let monitor: NWPathMonitor = NWPathMonitor()
public private(set) var isConnected:Bool = false
public private(set) var connectionType:ConnectionType = .unknown
init() {
print("init")
let queue = DispatchQueue.global(qos: .background)
monitor.start(queue: queue)
}
public enum ConnectionType {
case cellular
case wifi
case ethernet
case unknown
}
public func startMonitoring() {
monitor.pathUpdateHandler = { [weak self] path in
self?.isConnected = path.status == .satisfied
self?.getConnectionType(path)
NotificationCenter.default.post(name: NSNotification.Name("connectionType"),
object: nil)
}
}
public func stopMonitoring() {
monitor.cancel()
}
private func getConnectionType(_ path:NWPath) {
if path.usesInterfaceType(.wifi) {
connectionType = .wifi
} else if path.usesInterfaceType(.cellular) {
connectionType = .cellular
} else if path.usesInterfaceType(.wiredEthernet) {
connectionType = .ethernet
} else {
connectionType = .unknown
}
}
}
and this is view in which I want to monitor:
class ViewController: UIViewController {
private var networkMonitor:NetworkMonitor?
private let notificationCenter = NotificationCenter.default
private let networkConnectivityView = NetworkConnectivityView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(networkConnectivityView)
notificationCenter.addObserver(self,
selector: #selector(listeningNetworkConnection),
name: NSNotification.Name("connectionType"),
object: nil)
notificationCenter.addObserver(self, selector: #selector(appDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.willResignActiveNotification, object: nil)
}
@objc func appDidBecomeActive() {
networkMonitor = NetworkMonitor()
networkMonitor?.startMonitoring()
}
@objc func appMovedToBackground() {
networkMonitor?.stopMonitoring()
networkMonitor = nil
}
@objc private func listeningNetworkConnection() {
DispatchQueue.main.async { [weak self] in
self?.updateUI()
}
}
private func updateUI() {
guard let networkMonitor = networkMonitor else {
return
}
if networkMonitor.isConnected{
print("connected")
networkConnectivityView.configure(with: "Connected")
} else {
print("Not connected")
networkConnectivityView.configure(with: "Not Connected")
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
networkConnectivityView.frame = CGRect(x: 0,
y: 0,
width: view.frame.size.width,
height: 50)
networkConnectivityView.center = view.center
}
}
This is working fine but the problem is whenever I want to use this in other view controllers I have to duplicate the code for assigning again NetworkMonitor in appDidBecomeActive and making it nil in appMovedToBackground.
So please help me in improving my approach so that I just need to call startMonitoring in view controllers
have you considered
UIApplicationDelegate
methodsapplicationWillResignActive(_:)
andapplicationWillEnterForeground(_:)
? Also maybe it's a good idea to make yourNetworkMonitor
a Singleton and callstopMonitoring()
andstartMonitoring()
in respective methods ofUIApplicationDelegate