◉RORK LABJP
●EXPO — EAS Observe now records native crashes (Oct 7). On SDK 57, update to 57.0.21 or later●SDK 58 — SDK 58 Beta has been out since Sep 15. The stable date is still unconfirmed●RN 0.88 — React Native 0.88.x is scheduled for Oct 12, 3 days left●Q&A — People are asking why expo-widgets render blank only in production builds●RORK — GPT-6.1 Sol was added on Sep 29, available on Pro and Max plans●NEW — Building an app for a client? Decide who owns the publishing account first●EXPO — EAS Observe now records native crashes (Oct 7). On SDK 57, update to 57.0.21 or later●SDK 58 — SDK 58 Beta has been out since Sep 15. The stable date is still unconfirmed●RN 0.88 — React Native 0.88.x is scheduled for Oct 12, 3 days left●Q&A — People are asking why expo-widgets render blank only in production builds●RORK — GPT-6.1 Sol was added on Sep 29, available on Pro and Max plans●NEW — Building an app for a client? Decide who owns the publishing account first
Articles/App Dev
◇ App Dev/2026-07-03Intermediate

Making Your Rork Max App Resilient to Dropped and Restored Connections: Offline Detection and Retry with NWPathMonitor

Build networking that survives a lost signal in your Rork Max native Swift app with NWPathMonitor. Detect offline states, respect Low Data Mode and cellular, and auto-resend queued work on reconnect — all with working Swift code.

Rork Max235NWPathMonitorNetwork3Offline3Swift48iOS115

✦ Premium Article

Back when I was handing out a beta of a notes app, I received a handful of reports saying "the note I wrote disappeared." I couldn't reproduce it on my own device. Digging through the logs, the one thing they had in common was that the save had happened inside a subway car or an elevator. Tapping save with no connection failed silently, and the screen simply closed as if nothing had gone wrong. To the user, it looked like the note had been saved.

As an indie developer, I find this kind of bug the most insidious. A crash is at least visible. Data that vanishes quietly erodes trust while nobody notices.

With Rork Max's native Swift, you can watch the state of the network path in real time using NWPathMonitor from Apple's Network framework. In this article we'll wrap that monitoring into something the whole app can share, then build offline signaling, behavior that adapts to the connection type, and automatic resend on recovery — all with code that actually runs.

Why "ping the server to check" is the wrong instinct

When people think about detecting offline states, a common first idea is to fire a lightweight request at the server on launch and read success or failure. I did exactly that at first. But the approach is weak in two ways.

First, it can't capture the possibility that the signal drops the instant after the ping succeeds. Connectivity changes continuously, so checking it at a single point in time tells you little.

Second, Apple itself discourages pre-flighting reachability. The NWPathMonitor documentation frames it clearly: judge whether you can connect by actually attempting the connection, and observe path changes with the monitor. Rather than deciding "can I get through?" before sending, the better posture is to keep watching whether a path exists right now, wait if there isn't one, and flush when it comes back.

NWPathMonitor reports the state of the currently available path across interfaces — Wi-Fi, cellular, wired. And it tells you more than "connected or not": it also reveals whether that path is expensive (cellular, tethering) and whether it's constrained (Low Data Mode).

Wrap NWPathMonitor in a single monitor

Start by consolidating the monitoring in one place. Creating an NWPathMonitor per screen leads to scattered state and missed updates. Hold exactly one for the app and expose it as an ObservableObject that SwiftUI can subscribe to.

import Foundation
import Network
import Combine
 
@MainActor
final class NetworkMonitor: ObservableObject {
    static let shared = NetworkMonitor()
 
    @Published private(set) var isConnected = true
    @Published private(set) var isExpensive = false      // cellular, tethering
    @Published private(set) var isConstrained = false     // Low Data Mode
    @Published private(set) var pathStatus: NWPath.Status = .satisfied
 
    private let monitor = NWPathMonitor()
    private let queue = DispatchQueue(label: "NetworkMonitor")
 
    private init() {
        monitor.pathUpdateHandler = { [weak self] path in
            // pathUpdateHandler is called on a background queue
            Task { @MainActor in
                self?.apply(path)
            }
        }
        monitor.start(queue: queue)
    }
 
    private func apply(_ path: NWPath) {
        pathStatus = path.status
        isConnected = path.status == .satisfied
        isExpensive = path.isExpensive
        isConstrained = path.isConstrained
    }
 
    deinit {
        monitor.cancel()
    }
}

Two things matter here. pathUpdateHandler is invoked on the dedicated queue you passed to start(queue:) — a background queue. Touching @Published directly there moves UI updates off the main thread and causes warnings and flicker. That's why we hop to the main actor with Task { @MainActor in } before applying anything.

The second is that monitor.start must be called exactly once. Making the ObservableObject a single shared instance also guards against starting it more than once.

If you scaffold this with a Rork Max prompt, phrase it like this to get a close skeleton:

Using the Network framework's NWPathMonitor, create a @MainActor
ObservableObject that publishes isConnected / isExpensive / isConstrained
via @Published. Marshal the pathUpdateHandler result onto the MainActor
before applying it.

The generated code is usually usable as-is once you confirm the pathUpdateHandler isn't touching @Published off the main thread and that start(queue:) isn't called more than once.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Take home a working NetworkMonitor ObservableObject that lets any SwiftUI view subscribe to connectivity state
✦Learn to translate not just path.status but isExpensive and isConstrained into concrete UX decisions
✦Get a reconnect-triggered send queue that flushes failed requests the moment connectivity returns, plus the production pitfalls
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $15 for lifetime access
View Membership →

Related Articles

⬡ Dev Tools2026-04-05
Rork Max × WidgetKit & Live Activities in Practice — From Home Screen to Dynamic Island
A complete guide to implementing iOS Widgets, Lock Screen widgets, and Dynamic Island Live Activities with Rork Max. Covers WidgetKit fundamentals, Timeline update strategies, App Intents integration, and monetization.
◇ App Dev2026-04-26
Native iOS Apps with Rork: SwiftUI to TestFlight
New iPhone projects in Rork are generated in Swift and SwiftUI, and Rork Pro carries them all the way to the App Store. How to tell an old Expo project from a new one, costs in credits, the skeleton prompt, device testing, when to drop into Xcode, and TestFlight submission.
◈ Getting Started2026-09-08
Whether You Need Rork Max Is Answered by Your Permissions, Not the Price Page
When I cannot decide between standard Rork and Rork Max, I stop reading the price page. Instead I pull every OS capability my app actually asks for out of app.json and Info.plist, then sort them into what Expo covers, what a config plugin covers, and what truly needs native Swift.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links