Survive deleted-and-saved @Models on the started-run navigation path
TestFlight 2.3 (125) "crashed when watch ended an exercise": the
isDeleted guard from 85e1582 only covers the delete→save window. Once
the deletion is saved the model unregisters — isDeleted reads false
again, modelContext goes nil, and any persisted-property read still
traps (_InitialBackingData.getValue). StartedWorkoutNavigator retained
the run's @Model in @State for the whole workout, so an observer
remove/re-add churn (e.g. iCloud reachability flapping) invalidated it
underneath the pushed screen, and the watch's completion push triggered
the rebuild that read it.
Two layers: the fromLive/SplitDetailView guards now also require a
non-nil modelContext, and StartedWorkoutNavigator pushes a plain id
route, re-fetching the entity fresh on every destination build — a
re-imported run resolves to its live instance; a gone run shows a
placeholder instead of trapping.
Claude-Session: https://claude.ai/code/session_01PVNBVKp5bcq52X722uMjwT
This commit is contained in:
@@ -62,8 +62,14 @@ extension WorkoutDocument {
|
||||
/// map — eagerly for *every* row in the parent list, including during the view-graph
|
||||
/// update that fires the instant a workout is deleted. Any map of an entity not
|
||||
/// already known to be live must go through this guard.
|
||||
///
|
||||
/// `isDeleted` alone is not enough: it is true only between `context.delete()` and
|
||||
/// `context.save()`. Once the deletion is saved the model becomes *unregistered* —
|
||||
/// `isDeleted` reads false again, `modelContext` goes nil, and any persisted-property
|
||||
/// read still traps. A `@Model` retained across time (not freshly fetched) can reach
|
||||
/// this map in that state, so check both.
|
||||
init?(fromLive workout: Workout) {
|
||||
guard !workout.isDeleted else { return nil }
|
||||
guard !workout.isDeleted, workout.modelContext != nil else { return nil }
|
||||
self.init(from: workout)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user