Become a professional iOS developer
Get started with iOS 12 and Swift 4
Sign up for our iOS development course Zero to App Store to learn iOS development with Swift 4, and start with your professional iOS career.
Detecting an iOS app’s internet connectivity is useful, especially if you want to check if the internet is reachable prior to making a network request.
Before iOS 12, a code snippet called Reachability was the de facto approach to determining if the internet could be accessed. iOS 12 introduces a new component, called NWPathMonitor
, that makes detecting internet reachability easier and more insightful.
In this article, we’ll discuss:
Reachability
(prior to iOS 12)NWPathMonitor
(iOS 12+)Ready? Let’s go.
If your app supports iOS versions before iOS 12, you’ll want to use the older Reachability component. It uses the SCNetworkReachability
class to create a network socket, and to listen for changes. Fortunately, that’s all abstracted away.
We can use Reachability
as follows. First, we’ll create a closure like this:
let onUpdate = { reachability in
if reachability.connection == .wifi {
print("We have WiFi!")
} else if reachability.connection == .cellular {
print("We have 3G/4G!")
} else {
print("No internet :-(")
}
}
Then, we’re creating a Reachability
object and assign the onUpdate
closure to two of its properties:
let reachability = Reachability()
reachability?.whenReachable = onUpdate
reachability?.whenUnreachable = onUpdate
The closure we defined earlier is now called whenever the network connectivity status changes. We could have used two different closures, but it’s simpler to use just one. After all, the connection
property only has 3 states: .none
, .cellular
and .wifi
.
It’s also smart to create a reachability
property in your code, so the object is retained throughout the lifetime of your app. It’s also an effective use case for a singleton, in fact.
Finally, we need to start the reachability component to get connectivity updates. Here’s how:
do {
try reachability.startNotifier()
} else {
print("Error starting Reachability...")
}
In the above code we use error handling to check if the notifier could be started. When it can’t, we can respond by default with a state that has no internet connection.
When using Reachability
, don’t use a hard-coded IP address to check if a particular webserver is reachable. Use a domain name instead, otherwise your app becomes incompatible with either IPv4 or IPv6 networks.
Sign up for our iOS development course Zero to App Store to learn iOS development with Swift 4, and start with your professional iOS career.
At WWDC 2018, Apple introduced the NWPathMonitor
component as part of the Network
framework for iOS 12. This means we won’t have to rely on 3rd-party code anymore to monitor network changes.
The way NWPathMonitor
works is similar to Reachability
, but it gives a lot more information about the network we’re connected to. In short, we’ll need to create the NWPathMonitor
, register an update handler, and start the update notifier.
First, let’s set up the component itself:
let monitor = NWPathMonitor()
Again, you’ll want to create a strong reference to this NWPathMonitor
object somewhere, so it’s retained in memory. Adding it as a property to your AppDelegate
class is one approach to do that.
You can also provide the NWPathMonitor
initializer with the type of network you want to monitor. Like this:
let monitor = NWPathMonitor(requiredInterfaceType: .wifi)
This will monitor changes for just the WiFi network. You can also get updates on these types of interfaces:
.cellular
for 3G/4G.loopback
for localhost or lo0
.other
for virtual networks or unknown network types.wifi
for good ol’ WiFi.wiredEthernet
if you managed to plug an RJ45 in your iPhone… (no, really, the Network
framework works on iOS, macOS and tvOS)Once you’ve set up the component, you can register for changes in network connectivity. Like this:
monitor.pathUpdateHandler = { path in
if path.status == .satisfied {
print("Yay! We have internet!")
}
}
In the above closure, the path
parameter of type NWPath
contains a lot of information about the network:
isExpensive
returns true
when the path uses an interface that’s considered expensive, such as 3G/4G via a paid cellular data planstatus
, of type NWPathStatus, indicates if a network request could be successfully made over this network pathavailableInterfaces
contains an array of network interfaces that can be used for this pathsupportsDNS
, supportsIPv4
and supportsIPv6
can be used to determine if the path can use DNS, IPv4 and IPv6 (esp. helpful for local networking)You can use the function usesInterfaceType(_:)
to check which interface type this network path uses. This is the most effective way to figure out if your app is connected over WiFi, cellular or ethernet.
Here’s how:
if path.usesInterfaceType(.wifi) {
print("It's WiFi!")
} else if path.usesInterfaceType(.cellular) {
print("3G/4G FTW!!!")
}
When the status
property has value .satisfied
, you can be certain there’s internet connectivity via that network path. When it’s .unsatisfied
, the network path isn’t available and there is no internet access.
The third case of status
is .requiresConnection
. It’s unclear what it does exactly, for a lack of documentation, but it appears that this state indicates that the path could become available in near future, i.e. when a VPN connection or captive portal finishes setting up an internet connection.
Finally, just as before, we need to start the monitor to receive connectivity updates. You can do this by assigning the monitor to a background dispatch queue, like this:
let queue = DispatchQueue.global(qos: .background)
monitor.start(queue: queue)
The monitor will now start receiving network path updates. So, whenever the network changes, the closure will get called and you can respond to changes in internet connectivity.
An interesting scenario occurs when you set requiredInterfaceType
to .cellular
, sign on to a WiFi network, and then wait for network updates. The path will show as “unsatisfied (Interface type cellular is required by parameters)” and path.usesInterfaceType(.wifi)
will return true
. This kind of fine-grained control and information is perfect for mediating the best-available network path, such as downgrading to cellular when WiFi won’t work.
You might wonder why you’d want to monitor for internet connectivity when you can just make an HTTP request and check if it succeeds. Let’s discuss the use cases for practical connectivity detection.
It’s important to understand that simply waiting for a request to succeed has a few disadvantages:
If you know that your app is connected to the internet before making a request, you can more efficiently make that request. When there’s no connectivity, you don’t even have to attempt to make that request.
Some apps also rely on an active internet connection. Take database platforms like Firebase and Parse Server, for example. They support a so-called offline mode, in which data that’s written to the database is temporarily cached locally when there’s no active internet connection.
An app’s users don’t notice anything from this behavior, because they can use the app regardless of having internet connectivity or not. When the network comes back online, changes they made in the app are sent to the server as if there was no lapse in connectivity at all. This functionality is crucial in making offline-first apps.
Sign up for our iOS development course Zero to App Store to learn iOS development with Swift 4, and start with your professional iOS career.
The NWPathMonitor
component gives you more insight in the state of network connectivity, and allows you to make sensible choices about network requests prior to making them.
The component is more advanced than Reachability
, although the simplest approach is still as easy as registering a callback and starting to monitor network changes. Neat!
Want to learn more? Check out these resources:
Hi, I'm Reinder.
I help developers play with code.