Contents

rasheed-k-mozaffar/reachable

Reachable is a lightweight Swift package for monitoring network connectivity on Apple platforms.

Why Reachable

  • Simple observable API for SwiftUI and app state
  • AsyncStream support for structured concurrency
  • Combine publisher support for existing reactive pipelines
  • Callback-based hooks for reconnect and disconnect events
  • SwiftUI helpers for common offline UI patterns
  • MockNetworkMonitor for previews and tests

Platforms

  • iOS 17+
  • iPadOS 17+ via iOS support
  • macOS 14+
  • watchOS 10+

Installation

Add Reachable to your Package.swift:

.package(url: "https://github.com/your-org/Reachable.git", from: "1.0.0")

Then depend on the product:

.product(name: "Reachable", package: "Reachable")

Quick Start

Create a monitor and read the current connection state:

import Reachable

let monitor = NetworkMonitor()

if monitor.isConnected {
    print("Online")
} else {
    print("Offline")
}

If you want more detail, inspect the full state snapshot:

let state = monitor.state

print("Connected:", state.isConnected)
print("Type:", state.connectionType)
print("Expensive:", state.isExpensive)
print("Constrained:", state.isConstrained)
print("VPN:", state.isVPN)

SwiftUI

Use NetworkMonitor.shared for app-wide injection:

import Reachable
import SwiftUI

@main
struct DemoApp: App {
    @State private var monitor = NetworkMonitor.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
                .networkMonitor(monitor)
        }
    }
}

struct ContentView: View {
    @Environment(\.networkMonitor) private var monitor

    var body: some View {
        VStack(spacing: 12) {
            Text(monitor.isConnected ? "Online" : "Offline")
            Text("Connection: \(String(describing: monitor.connectionType))")
            Text(monitor.isConstrained ? "Low Data Mode" : "Unconstrained")
        }
        .networkRequired()
    }
}

You can also present built-in offline UI:

import Reachable
import SwiftUI

struct Screen: View {
    var body: some View {
        ZStack(alignment: .top) {
            Content()
            NetworkStatusBanner()
        }
        .networkRequired()
    }
}

Or provide a custom disconnected overlay:

ContentView()
    .networkRequired { state in
        VStack(spacing: 8) {
            Text("Offline")
                .font(.headline)
            Text("Current type: \(String(describing: state.connectionType))")
                .font(.caption)
        }
        .padding()
        .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 16))
    }

Callbacks

Reachable can notify you when the network comes back, drops, or changes transport type:

import Reachable

let monitor = NetworkMonitor()

let reconnectToken = monitor.onReconnect {
    print("Connection restored")
}

let disconnectToken = monitor.onDisconnect {
    print("Connection lost")
}

let typeToken = monitor.onConnectionTypeChange { newType in
    print("Now using:", newType)
}

Keep the returned tokens alive for as long as you want the callbacks to remain active.

AsyncStream

import Reachable

let monitor = NetworkMonitor()

Task {
    for await state in monitor.stateStream {
        print("Connected:", state.isConnected)
        print("Type:", state.connectionType)
        print("Expensive:", state.isExpensive)
    }
}

Combine

import Combine
import Reachable

let monitor = NetworkMonitor()
let cancellable = monitor.statePublisher
    .sink { state in
        print("Current state:", state)
    }

Mocking and Previews

import Reachable
import SwiftUI

#Preview {
    let monitor = MockNetworkMonitor(initialState: .disconnected())

    return ContentView()
        .networkMonitor(monitor)
}

You can drive preview or test updates with monitor.state = ... or monitor.setState(...).

Core Types

  • NetworkMonitor: the main NWPathMonitor-backed monitor
  • MockNetworkMonitor: a manually controlled monitor for previews and tests
  • NetworkState: the full snapshot of current network conditions
  • ConnectionStatus: connected or disconnected
  • ConnectionType: wifi, cellular, ethernet, vpn, or unknown

Common Use Cases

  • Show an offline banner or overlay
  • Pause syncing while disconnected
  • Retry work when connectivity returns
  • Respect Low Data Mode with isConstrained
  • Avoid large transfers on expensive connections

Documentation

The package also ships with DocC documentation covering:

  • monitoring connectivity
  • using Reachable in SwiftUI
  • testing connectivity-driven UI

Package Metadata

Repository: rasheed-k-mozaffar/reachable

Default branch: main

README: README.md