Fix launch crash: start telemetry after Core Data initialization - #1519
Conversation
Since nightscout#1367, AppDelegate.didFinishLaunching resolved TelemetryClient eagerly, constructing the APS/device graph before the persistent stores were loaded. Pump and CGM simulators save immediately, so launches crashed with "NSPersistentStoreCoordinator has no persistent stores" (storeGlucose / storeBatteryStatus queues). Telemetry now starts at the end of loadServices(), after the Core Data stack is initialized; the foreground-transition hook receives its reference from there and no-ops before that.
jwoglom
left a comment
There was a problem hiding this comment.
Cherry-picked this onto latest dev and validated it doesn't crash on startup
There was a problem hiding this comment.
Can confirm this works in a build to iPhone 16 Pro and iPhone 12 Mini, both running iOS 27 stable and built from XCode 27. Appears to build as expected and the app now launches instead of crashing. This is not a full test of the dev branch latest state, just confirming that the app no longer fatally crashes when building this branch as compared to the current dev branch where it does fatally crash.
bjornoleh
left a comment
There was a problem hiding this comment.
Confirmed that the app on my phone no longer crashes when running this update. Did previously crash with current dev with sim pump/CGM.
Approving based on a quick, successful test.
Problem
Debug/simulator launches of current dev crash within seconds:
Crashing queues are
NSManagedObjectContext: storeGlucoseandstoreBatteryStatus.Cause
Since #1367,
TelemetryClient.sharedresolves through the DI container with eagerinjectServices.AppDelegate.didFinishLaunchingWithOptionscalls it at launch, which resolvesAPSManager+FetchGlucoseManagerand thereby constructsBaseDeviceDataManager— the whole APS/device graph — beforeCoreDataStack.initializeStack()has finished loading the persistent stores.The CGM and pump simulators deliver status/readings immediately on construction, so their first Core Data save races the store load and aborts the app. Real hardware usually wins the race (BLE reconnect latency), which is why reports cluster on simulator-configured dev setups; a Debug/TSAN build widens the window further. The launch-order log signature: a healthy launch logs
Successfully loaded persistent storebeforePumpManagerStateis persisted; a crashing one persistsPumpManagerStateimmediately and never reaches the store-load line.Fix
AppDelegateno longer resolves services at launch (only the Crashlytics gate remains, which touches plists only). Telemetry starts at the end ofTrioApp.loadServices()— i.e. strictly after Core Data initialization — with the identical cadence sequence as before (install ID, cold-launch recording, SHA-change ping, recurring timer, overdue check). The foreground-transition hook receives itsTelemetryClientreference fromloadServices()and no-ops before that.This deliberately does not reintroduce the old
injectIfNeededdeferral; eager injection stays, only the call site moves behind the initialization barrier.Notes
TrioRemoteControl.sharedindidReceiveRemoteNotificationwhen a push cold-launches the app). It predates Refactor: Dependency Injection Hygiene #1367 and is left for a follow-up.