Network Path Monitoring

How do you use the NWPathMonitor to monitor network availability?

Do You Need To Monitor Network Availability?

Before iOS 11, if you started a URLSession to make a network connection it would fail at once if the network was not available. To avoid retrying a failed connection, the SCNetworkReachability API could check the reachability of a target host.

In iOS 11, Apple recommended you stop using the reachability API to check network availability before attempting a connection. Instead you configure a URLSession to wait for connectivity.

The wait for connectivity model works better for creating connections but I still sometimes want to show the user a network status indicator.

Creating A Path Monitor

Apple released the Network framework in iOS 12, macOS 10.14. It includes a NWPathMonitor that is now the preferred way to monitor changes to network status. The three steps to monitor network changes:

  1. Create a NWPathMonitor.
  2. Call the start method of the path monitor passing a queue that will receive path change events.
  3. Receive path changes in the pathUpdateHandler.

I’m wrapping the monitor in an ObservableObject which I’m using to publish the network status:

class PathMonitor: ObservableObject {
  @Published private(set) var status: NWPath.Status

  private let pathMonitor = NWPathMonitor()
  private let pathMonitorQueue = DispatchQueue(label: "NWPathMonitor")

  init(status: NWPath.Status = .unsatisfied, active: Bool = true) {
    self.status = status
    
    if active {
      enablePathMonitor()
    }
  }

  private func enablePathMonitor() {
    pathMonitor.pathUpdateHandler = { path in
      DispatchQueue.main.async {
        self.status = path.status
      }
    }
    pathMonitor.start(queue: pathMonitorQueue)
  }
}

Notes:

  • When working with SwiftUI previews I disable the active path monitoring and pass a value for the status.
  • The path monitor calls the pathUpdateHandler on the path monitor queue when the network path changes. I make sure to update the published property back on the main queue.

Using The Path Monitor

As a quick example, I’ve created a path monitor and passed it to a content view using the SwiftUI environment:

@main
struct NWMonitorApp: App {
  @StateObject private var pathMonitor = PathMonitor()
    
  var body: some Scene {
    WindowGroup {
      NavigationStack {
        ContentView()
        .environmentObject(pathMonitor)
      }
    }
  }
}

The NWPath.Status value is an enum with three values:

  • unsatisfied: Path not available.
  • satisfied: Path available
  • requiresConnection: Path not available but attempting a connection may make it available.

I created a small extension on NWPath.Status to return a message, colour and SFSymbol name for each of the three possible values:

extension NWPath.Status {
  var message: String {}
  var color: Color {}
  var image: String {}
}

Then in a status view I have a section for the network status:

struct ContentView: View {
  @EnvironmentObject private var pathMonitor: PathMonitor
    
  var body: some View {
    List {
      Section("Network Status") {
        networkLabel
      }
    }
    .listStyle(.grouped)
    .navigationTitle("Network Monitor")
  }
}

The networkLabel shows the status message and icon:

  private var networkLabel: some View {
    Label {
      Text(pathMonitor.status.message)
    } icon: {
      Image(systemName: pathMonitor.status.image)
        .foregroundColor(pathMonitor.status.color)
    }
  }

Network status red triangle not available

Network Path Details

For my needs the network path status is often enough but the NWPath value contains a lot of extra details which can be useful when diagnosing issues:

Capabilities

  • supportsIPv4: can the path route IPv4 traffic?
  • supportsIPv6: can the path route IPv6 traffic?
  • supportsDNS: does the path have a DNS server configured?
  • isConstrained: is the interface in Low Data Mode?
  • isExpensive: is this a cellular or personal hotspot interface?

Note: these properties are always false when running on the iOS simulator.

Interfaces

The availableInterfaces property of NWPath is a collection of the available interfaces (NWInterface) in order of preference. The NWInterface type includes the name and interface type (wifi, cellular, wiredEthernet, loopback or other).

The gateways property of NWPath is a list of the gateways configured on the available interfaces. Each gateway is an NWEndpoint.

Here’s how some of those properties look when running on an iPhone connected to WiFi:

Network Monitor showing available status. IPv4, IPv6 and DNS support, not  constrained or expensive. WiFi and cellular interfaces.