Guard NavigationLink destination inits against deleted @Models
A closure-based NavigationLink builds its destination view eagerly for every row on every parent-list body evaluation — including the view-graph update SwiftUI runs the instant SyncEngine.delete does context.delete + save. Mapping the row's just-deleted @Model to a document there reads a persisted property on a dead model, which traps in SwiftData (_InitialBackingData.getValue -> assertionFailure). This is the "Crashed when deleted a workout" TestFlight report on 2.3 (124). Add WorkoutDocument(fromLive:) (nil when isDeleted) + a .deletedPlaceholder and route every destination-init / updatedAt-absorb map through it: phone WorkoutLogListView + SplitDetailView (read split.id) and watch WorkoutLogListView. Fixes the whole crash class, not just the report. Claude-Session: https://claude.ai/code/session_01BQcEWmAPA78338QuEwRkAh
This commit is contained in:
@@ -44,7 +44,11 @@ struct WorkoutLogListView: View {
|
||||
|
||||
init(workout: Workout) {
|
||||
self.workout = workout
|
||||
_doc = State(initialValue: WorkoutDocument(from: workout))
|
||||
// A closure-based `NavigationLink` builds this destination eagerly for every
|
||||
// row in the parent list — including during the view-graph update that fires
|
||||
// the instant a workout is deleted — so map only a live entity here; a deleted
|
||||
// one traps in SwiftData. The placeholder is never shown (the row is gone).
|
||||
_doc = State(initialValue: WorkoutDocument(fromLive: workout) ?? .deletedPlaceholder)
|
||||
}
|
||||
|
||||
private var sortedLogs: [WorkoutLogDocument] {
|
||||
@@ -166,7 +170,9 @@ struct WorkoutLogListView: View {
|
||||
// Absorb edits made in pushed children (ExerciseView/Plan/Notes) once the
|
||||
// cache reflects them, so the list shows live status on return.
|
||||
.onChange(of: workout.updatedAt) { _, _ in
|
||||
doc = WorkoutDocument(from: workout)
|
||||
// Skip if the entity was deleted out from under us (e.g. a remote delete
|
||||
// while this screen is open) — mapping a deleted @Model traps.
|
||||
if let fresh = WorkoutDocument(fromLive: workout) { doc = fresh }
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
|
||||
Reference in New Issue
Block a user