damus
damus copied to clipboard
Fix TestFlight error: Unexpectedly found nil” (damus/ContentView.swift:305) Refine ContentView damus_state bootstrap flow
problem
fixes "nil" crash from TestFlight error review https://github.com/damus-io/damus/issues/3279
solution overview
- Replaces the force-unwrapped damus_state! usages in ContentView with a guarded withDamusState helper so sheets, overlays, and URL handlers only run when the state is ready—resolving the TestFlight crash (“Optional unwrap in ContentView... Unexpectedly found nil”).
- Boots DamusState once via .task, defers post-connect setup until initialization is complete, and logs/returns early when lifecycle notifications arrive before the state is available.
- Confirms ShareExtension builds cleanly via xcodebuild -scheme ShareExtension -configuration Debug -destination 'generic/platform=iOS Simulator' build, while the simulator now exits the loading spinner and shows the timeline.
testing
ran in xcode iOS Simulator to ensure damus compiles, runs, and does not crash. could not recreate a crash
technical description for @danieldaquino
Technical Overview
- damus/damus/ContentView.swift now boots DamusState exactly once via .task { await startInitialConnectIfNeeded() }, so the initial spinner transitions only after connect() finishes.
- Added @State flags (hasStartedInitialConnect, hasCompletedPostConnectSetup) to fence the initialization path; connect() is marked @MainActor and hands off to
runPostConnectionSetupIfNeeded when the state exists.
- Every sheet/overlay/notification entry point calls the guarded withDamusState helper at damus/damus/ContentView.swift:253, returning AnyView and early-exiting when damus_state is
still nil. This replaces the prior damus_state! force-unwraps that triggered the TestFlight “Unexpectedly found nil” crash.
- URL / wallet / follow handlers (e.g., attachOpenURLAndTimerHandlers and attachNotificationHandlers) now bail with structured logging when invoked before initialization and resume
work with a concrete state value; lifecycle callbacks reuse the post-connect helper instead of duplicating setup.
- The main navigation container was factored into contentView(for:), mainNavigation(for:), and tabContainer(for:) to keep the view tree simpler and reduce SwiftUI’s type-checking load
that had been causing ShareExtension compile failures on the local relay branch.
Verification
- CLI build: xcodebuild -scheme ShareExtension -configuration Debug -destination 'generic/platform=iOS Simulator' build
- Simulator: confirmed the app leaves the loading spinner and loads the timeline.
Please look closely at flows that previously relied on early damus_state (sheet presentation, notification handlers, background reactivation) to ensure no regressions with the guarded
logic.
Thank you @alltheseas for this!
Do you have rough stats on how often you were seeing the crash before the fix?
Thank you @alltheseas for this!
Do you have rough stats on how often you were seeing the crash before the fix?
per TestFlight submissions about ~6% of reported crashes