Network Reachability With Swift
Are you looking for a reliable way to check the network state of your users' devices? Come and read about Network Reachability.
A day, I had been using the Alamofire
NetworkReachabilityManager class—to check the network state of the user’s device—and suddenly I have found a bug because of an edge-case scenario. At that point, I decided to learn well how this class works and how to contribute to fix the issue.
The result is in this Pull Request: Alamofire #2060.
I think that network reachability is an interesting topic to know, therefore I want to share with you how it works.
What Is Network Reachability?
Network Reachability is the network state of the user’s device. We can use it to understand if the device is offline or online using either wifi or mobile data.
To read these informations, we can use the interface of
SCNetworkReachability provided by the framework
SystemConfiguration. We can use it to read the network informations both synchronously and asynchronously.
Let’s start step by step using this interface.
Once imported the framework
SystemConfiguration merely with:
The first step is the instantiation of a
SCNetworkReachability object. There are mainly two ways to do it:
1. Using a hostname:
We can use the function
SCNetworkReachabilityCreateWithName which needs a hostname as argument:
The first parameter is the allocator, we can pass
nil to use the default one.
SCNetworkReachabilityCreateWithName returns an optional value, therefore we have to unwrap it.
2. Using a network address reference:
Once we have a
SCNetworkReachability object, we are ready to use the network state information.
SCNetworkReachability provides these information with a set of flags—
I copy here, from the official documentation, the list of flags:
The specified node name or address can be reached via a transient connection, such as PPP.
The specified node name or address can be reached using the current network configuration.
The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set, the kSCNetworkReachabilityFlagsConnectionOnTraffic flag, kSCNetworkReachabilityFlagsConnectionOnDemand flag, or kSCNetworkReachabilityFlagsIsWWAN flag is also typically set to indicate the type of connection required. If the user must manually make the connection, the kSCNetworkReachabilityFlagsInterventionRequired flag is also set.
The specified node name or address can be reached using the current network configuration, but a connection must first be established. Any traffic directed to the specified name or address will initiate the connection.
The specified node name or address can be reached using the current network configuration, but a connection must first be established.
The specified node name or address can be reached using the current network configuration, but a connection must first be established. The connection will be established “On Demand” by the CFSocketStream programming interface (see CFStream Socket Additions for information on this). Other functions will not establish the connection.
The specified node name or address is one that is associated with a network interface on the current system.
Network traffic to the specified node name or address will not go through a gateway, but is routed directly to one of the interfaces in the system.
The specified node name or address can be reached via a cellular connection, such as EDGE or GPRS.
The specified node name or address can be reached using the current network configuration, but a connection must first be established. Any traffic directed to the specified name or address will initiate the connection. This flag is a synonym for connectionOnTraffic
We can easily read these flags using the function
SCNetworkReachabilityGetFlags which wants two parameters:
- An empty
SCNetworkReachabilityFlagsobject passed by reference—in this way the internal implementation of
SCNetworkReachabilityGetFlagsadds the flags to this object.
flags is a Set, we can check if a flag is available with the method
At this point, we have an instance of
SCNetworkReachability and we know how to read the flags. We are ready to check if the user’s device has internet connection.
To get this information, we can read the content of
SCNetworkReachabilityFlags with the following method:
If you have some doubts about the meaning of some flags, you can check the flags list in “Network Flags”.
And we can use the function above like this:
The example above is completely synchronous. This means that we don’t have to wait any completion handler to get the information which we’re looking for.
There are applications where the synchronous information is not enough. We may need an asynchronous callback which says when the network state is changed.
SCNetworkReachability provides the possibility to set a listener of network changes. We can achieve it with the following example:
Handler class we can start/stop listening with the methods
To keep this example as plain as possible,
checkReachability(flags:) doesn’t check if the network is reachable but just if the flags are changed. In a real scenario, we may want to check also if the device has an internet connection using the method
isNetworkReachable used in “Using Synchronously”.
Avoiding Manual Implementation
If we want to avoid bothering ourself making a manual implementation, we can use an open source library which provides a high-level interface to wrap
The most famous are:
An example where we should use the network reachability may be an App which reads some informations from a public API. If the user’s device doesn’t have internet connection, trying to fetch the data doesn’t make sense. Instead, we should listen the network state changes and start fetching the data once we receive the notification that the device has internet connection available.
With iOS 11, Apple introduced the property
waitsForConnectivity in the
URLSessionConfiguration to wait an internet connection before performing any network activity with
URLSession. This means that, with this property set to
true we don’t need to bother ourself checking manually the device’s connection and waiting a valid internet connection.
URLSession will do it under the hood.
Unfortunately, if we have to support also versions older than iOS 11—or if we perform network activities without using
URLSession—we must continue doing it manually.
Most of the apps which we develop have to use an internet connection to transfer data. Therefore, we should handle properly the reachability state of the user’s device—to understand if we can perform or postpone some actions handling the missing connection. It can improve battery life and user experience.