iOS - Checking the Network Status (Swift)

Today I am going to write about classic problem we all face in the app, Detecting network outage. There are times of bad internet connections or no connection at all. These could cause severe distress to app user. Even worse, if they continue and there is no way to let user know that app is not a problem but internet connection is, user might even uninstall the app blaming the wrong entity.

Although there are some improvement developer can add to make it better. For example, caching most frequently accessed content or showing placeholder in case network connection is slow or lost. However, certain times high quality and time sensitive content comes from online resource and if request fails, it is best approach to let user know of it. (In both the cases going from online to offline and other way around) In this case it is left to user how to deal with persisting network issue if that is so.

I have used Apple's native Reachability framework before. However, as I noticed this framework could very well detect the initial network state, but right after network changed it failed to consistently give me related notifications

As a solution, I moved to using AFNetworking (2.6.3). This worked really well for me for one of the side projects. First off, you will have to create a podfile and add the AFNetworking dependency to it as follows.


platform :ios, ‘8.0’
inhibit_all_warnings!
use_frameworks!

xcodeproj '<your_project_name>'

target '<your_project_name>' do
    pod 'AFNetworking', '~> 2.0’
end

Please note that how I have used a greedy operator. Using which it will only use all the minor version of 2.0. However, it will not pull any of the next major version (3.0, 4.0 and so on).

First off, you have to start listening for your network reachability status change notifications. So it's better to keep that code inside class that you know will outlive your application. It may be a singleton (You know they're bad in general) or you may also use AppDelegate which listens to network status change and post notification as it gets toggled.

Please note that I have used Swift 3.0 for this tutorial. Although it should not be too hard to switch to Swift 2.0 if you are still on it. Let me know if you face any issues making that conversion

In this case I am going to use AppDelegate.swift

First off import the AFNetworking module

import AFNetworking

Add the following code which will emit the notification upon receiving network status change from AFNetworkReachabilityManager


let NetworkReachabilityChanged = NSNotification.Name("NetworkReachabilityChanged")
var previousNetworkReachabilityStatus: AFNetworkReachabilityStatus = .unknown

AFNetworkReachabilityManager.shared().startMonitoring()
        AFNetworkReachabilityManager.shared().setReachabilityStatusChange { (status) in
            let reachabilityStatus = AFStringFromNetworkReachabilityStatus(status)
            var reachableOrNot = ""
            var networkSummary = ""
            var reachableStatusBool = false

            switch (status) {
            case .reachableViaWWAN, .reachableViaWiFi:
                // Reachable.
                reachableOrNot = "Reachable"
                networkSummary = "Connected to Network"
                reachableStatusBool = true
            default:
                // Not reachable.
                reachableOrNot = "Not Reachable"
                networkSummary = "Disconnected from Network"
                reachableStatusBool = false                
            }

            // Any class which has observer for this notification will be able to report loss of network connection
            // successfully.

            if (self.previousNetworkReachabilityStatus != .unknown && status != self.previousNetworkReachabilityStatus) {
                NotificationCenter.default.post(name: NetworkReachabilityChanged, object: nil, userInfo: [
                    "reachabilityStatus" : "Connection Status : \(reachabilityStatus)",
                    "reachableOrNot" : "Network Connection \(reachableOrNot)",
                    "summary" : networkSummary,
                    "reachableStatus" : reachableStatusBool
                ])
            }
            self.previousNetworkReachabilityStatus = status
        }

Below is a nice summary of what we are doing in the above code

  1. Start a network monitoring with singleton AFNetworkReachabilityManager object
  2. Add the block setReachabilityStatusChange which will get called every time network status changes
  3. Maintain and populate local variable which will enclose the metadata about current network status and will be sent over to respective observers upon network change
  4. We use local variable previousNetworkReachabilityStatus to keep track of previous network status. We will send notification out only if current network status is different from the one previously observed
  5. We also add check self.previousNetworkReachabilityStatus != .unknown to keep notification from firing on app startup irrespective of network state at the point
  6. If network state changes we send a notification NetworkReachabilityChanged with respective userInfo metadata.
  7. Assign current network state to previousNetworkReachabilityStatus

Now, let's go to an observer. Speaking of observer you need not add it to every viewController since that would mean lot of repetition. You may wish to put observer in one of the root view controller which can pass notification to other controllers which it owns.

override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(forName: NetworkReachabilityChanged, object: nil, queue: nil, using: {
            (notification) in
            if let userInfo = notification.userInfo {
                if let messageTitle = userInfo["summary"] as? String, let reachableOrNot = userInfo["reachableOrNot"] as? String, let reachableStatus = userInfo["reachabilityStatus"] as? String {
                    let messageFullBody = "\(reachableOrNot)\n\(reachableStatus)"
                    let alertController = UIAlertController(title: messageTitle, message: messageFullBody, preferredStyle: .alert)
                    let OKAction = UIAlertAction(title: "OK", style: .default)
                    alertController.addAction(OKAction)
                    self.present(alertController, animated: true, completion: nil)
                }
            }
        })
    }

Let's see what the code above does.

  1. We add an notification observer which listens for notification NetworkReachabilityChanged
  2. We assume notification bundles the necessary metadata into userInfo We unwrap this info to get necessary details of network switch
  3. Once we get required info we use UIAlertController to display it to user

In addition to displaying user an error message you may also dim the background or disable certain controls in order to avoid user from doing unwanted activities. (If proper care is not taken, doing certain online activities may cause an app to crash shifting blame from network to app)

This should be it as long as detecting network connection status change is concerned for an iOS app. I have used and I can assure this enough that this is pretty reliable API and you are safe to use it for production use. Let me know if you have any questions concerning this post or anything that related to mobile development. Happy to Help!

Jayesh Kawli

I am a web and mobile developer working at Wayfair in Boston, MA. I come to learn so many things during course of life and I write about things which helped me and feel like they can help others too.

Subscribe to Fresh Beginning

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!