Search code examples
iosswiftconnectionwifireachability

The correct way to manage wifi reachability changes?


Writing an app that requires the network. Run a method to check the WiFi is on and working, initially in the ViewController. So I got ...

wifiWorks = Reachability.isConnectedToNetwork()

This is defined like this ...

var wifiWorks: Bool = false {
  didSet {
    if wifiWorks {
        print("Wifi On")
        NotificationCenter.default.post(name: Notification.Name("WifiBon"), object: nil, userInfo: nil)
    } else {
        print("WiFi Off")
        NotificationCenter.default.post(name: Notification.Name("noWiFi"), object: nil, userInfo: nil)
    }
  }
}

Now if noWifi gets called it shows an alert that basically goes to the settings like this...

 func noWifi(notification:NSNotification) {
    DispatchQueue.main.async {
        //self.navigation.isHidden = true 
        let alert = UIAlertController(title: "Stop", message: "Your iPad isn't connected to the WiFi ...", preferredStyle: UIAlertControllerStyle.alert)
        let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in
            guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
                return
            }

            if UIApplication.shared.canOpenURL(settingsUrl) {
                UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
                    print("Settings opened: \(success)") // Prints true
                })
            }
        }
        alert.addAction(settingsAction)
        let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
        alert.addAction(cancelAction)
        self.present(alert, animated: true, completion: nil)
    }
}

At which point, my app isn't running any longer, the user is sitting in settings, and has to switch back to my app having (hopefully) turned the WiFi on. Back in my app I got this in the app delegate.

func applicationWillEnterForeground(_ application: UIApplication) {
    print("applicationWillEnterForeground")
    wifiWorks = Reachability.isConnectedToNetwork()
}

Which brings me back full circle, so you cannot continue with the app, cause it needs the WiFi.

My question, does this dance make sense; or was/is there a cleaner way to do this?


Solution

  • You can use Reachability's own Notifications, as it's GitHub page suggests:

    NotificationCenter.default.addObserver(self, selector: #selector(self.reachabilityChanged),name: ReachabilityChangedNotification,object: reachability)
    
    do{
      try reachability.startNotifier()
    }catch{
      print("could not start reachability notifier")
    }
    

    Callback:

    func reachabilityChanged(note: NSNotification) {
        let reachability = note.object as! Reachability
        if !reachability.isReachable {
            //you can show alert here
        }
    }
    

    Also be aware that user can turn on/off wifi without leaving your app, just by switching wifi toggle from Control Center. That's why you should not rely only on applicationWillEnterForeground method.