Best Approach for handling Network Connectivity Issue - Swift 5

544 views Asked by At

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

1

There are 1 answers

2
mkbrwr On

have you considered UIApplicationDelegate methods applicationWillResignActive(_:) and applicationWillEnterForeground(_:) ? Also maybe it's a good idea to make your NetworkMonitor a Singleton and call stopMonitoring() and startMonitoring() in respective methods of UIApplicationDelegate