How to check for network connection in SwiftUI using NWPathMonitor
NetworkMonitor
In order to check for any changes in the network connectivity, NWPathMonitor class can be used. It is provided by Apple as a part of Network framework.
With the introduction of @Observable macro in Swift 5.9, NetworkMonitor class can be implemented using the following code:
import Foundation
import Network
@Observable
class NetworkMonitor {
private let networkMonitor = NWPathMonitor()
private let workerQueue = DispatchQueue(label: "Monitor")
var isConnected = false
init() {
networkMonitor.pathUpdateHandler = { path in
self.isConnected = path.status == .satisfied
}
networkMonitor.start(queue: workerQueue)
}
}
First property is an NWPathMonitor observer, second property is a DispatchQueue where the monitor does its work. Third property is a bool value which will be tracked in the view in order to react on the changes in network connectivity.
NWPathMonitor is initialized without parameters, which means it will observe all connection types (wifi, celullar, wired ethernet and other).
Network unavailable view
With iOS 17, a new view for empty state was introduced, ContentUnavailableView
This new view can be conveniently used to create a warning view for a network connection error.
import SwiftUI
struct NetworkUnavailableView: View {
var body: some View {
ContentUnavailableView(
"No Internet Connection",
systemImage: "wifi.exclamationmark",
description: Text("Please check your connection and try again.")
)
}
}
#Preview {
NetworkUnavailableView()
}
Update UI
In order to use NetworkMonitor and update the view, NetworkMonitor has to be instantiated as a @State. Changes in the connection will update the value of isConnected flag and update the view. It can be implemented using this code:
struct ContentView: View {
@State private var networkMonitor = NetworkMonitor()
var body: some View {
if networkMonitor.isConnected {
Text("Internet Connection available")
} else {
ContentUnavailableView(
"No Internet Connection",
systemImage: "wifi.exclamationmark",
description: Text("Please check your connection and try again.")
)
}
}
}
Alternatively, NetworkMonitor can be injected as an environment object and used across the app.
@main
struct MyApp: App {
@State private var networkMonitor = NetworkMonitor()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(networkMonitor)
}
}
}
struct ContentView: View {
@Environment(NetworkMonitor.self) private var networkMonitor
var body: some View {
if networkMonitor.isConnected {
Text("Internet Connection available")
} else {
ContentUnavailableView(
"No Internet Connection",
systemImage: "wifi.exclamationmark",
description: Text("Please check your connection and try again.")
)
}
}
}
Testing
Network connection changes are not detected consistently in the Simulator, the suggestion is to perform testing on a real device.