How To Detect Internet Connectivity With NWPathMonitor

Written by Reinder de Vries on January 22 2019 in App Development

How To Detect Internet Connectivity With NWPathMonitor

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:

  • How you can check internet connectivity with Reachability (prior to iOS 12)
  • How you can check internet connectivity with NWPathMonitor (iOS 12+)
  • How to get connectivity updates, in case the network changes
  • Practical use cases for internet connectivity detection in iOS apps

Ready? Let’s go.

  1. Detect Internet Access With Reachability
  2. Detect Internet Access With NWPathMonitor
  3. Use Cases In Practical iOS Development
  4. Further Reading

Detect Internet Access With Reachability

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.

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.

Detect Internet Access With NWPathMonitor

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 plan
  • status, of type NWPathStatus, indicates if a network request could be successfully made over this network path
  • availableInterfaces contains an array of network interfaces that can be used for this path
    supportsDNS, 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.

Use Cases In Practical iOS Development

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:

  • It’s a waste of resources, because you’re making a request of which you’re not sure it’ll succeed
  • It’s a waste of a user’s time, because most requests that will fail due to internet connectivity will only do so after a timeout of a few seconds
  • It’s more complex to code, because in a request’s return handler, you’ll need to recover from connectivity issues (on top of data issues)

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.

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.

Further Reading

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:

Reinder de Vries

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.