Matthew's Dev Blog

A minimal reachability check for Swift

Why do reachability checks?

Reachability checks are used to give us an indication about whether the device has a usable network connection. If the check returns false, we can use that information to provide the user with better error.

How not to do reachability checks

Don't be tempted to use a reachability check to decide if to make an API call. All networking is unreliable - so reachability checks are, by definition, also unreliable. If you perform the check before the network call, and decide to not make that call, there's a risk you might be blocking a network call that may have succeeded.

A minimal reachability class in Swift

import Foundation
import Network

final class NetworkReachability {
	static let shared = NetworkReachability()
	private(set) var isReachable: Bool = false
	private let pathMonitor: NWPathMonitor = NWPathMonitor()

	private init() {
		self.pathMonitor.pathUpdateHandler = { [weak self] path in
			self?.handleUpdate(path)
		}
		self.pathMonitor.start(queue: DispatchQueue.global(qos: .utility))
	}

	private func handleUpdate(_ path: NWPath) {
		switch path.status {
		case .satisfied:
			self.isReachable = true
		case .unsatisfied, .requiresConnection:
			self.isReachable = false
		@unknown default:
			self.isReachable = false
		}
	}
}

This utility class has a isReachable property which is true if the device probably has a good connection, and false if it probably does not.

Note: TLS errors are not network problems, so they would cause the isReachable property to be true.

How to use it

// first check that a network error occurred
if let networkError {
    if NetworkReachability.shared.isReachable {
        // report possible network connection problem
    } else {
        // it's probably not a network problem
    }
}
Tagged with:

First published 20 November 2022