Guard every persisted read of retained workout models with isLive
A remotely deleted @Model traps on any persisted-property read, including the observed expression of .onChange, which SwiftUI evaluates on every body pass. Guard those expressions, the onAppear takeover read, and the summary sheet's document mapping. Claude-Session: https://claude.ai/code/session_01PKptrgbx74peTwHGRxBojv
This commit is contained in:
@@ -71,24 +71,30 @@ struct ExerciseView: View {
|
||||
}
|
||||
.onAppear {
|
||||
refreshDocIfNeeded()
|
||||
// Take over this run: the watch parks and locks it while we're editing here.
|
||||
services.watchBridge.setEditingWorkout(workout.id)
|
||||
// Take over this run: the watch parks and locks it while we're editing
|
||||
// here. Guarded — even `id` is a persisted property and traps when read
|
||||
// on an entity a remote delete has already reaped.
|
||||
if workout.isLive {
|
||||
services.watchBridge.setEditingWorkout(workout.id)
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
services.watchBridge.setEditingWorkout(nil)
|
||||
}
|
||||
// Reflect external changes (e.g. a set completed on the watch) live. Each edit
|
||||
// rewrites the whole workout file, so the cache always holds the latest — pulling
|
||||
// it in can't revert a newer local tap.
|
||||
.onChange(of: workout.updatedAt) { _, _ in
|
||||
// it in can't revert a newer local tap. The observed expression is evaluated on
|
||||
// every body pass, so it must be liveness-guarded like any persisted read.
|
||||
.onChange(of: workout.isLive ? workout.updatedAt : nil) { _, _ in
|
||||
absorbExternalUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
/// Pull an externally-changed workout into the working copy so the plan and notes
|
||||
/// update without leaving and re-entering the screen.
|
||||
/// update without leaving and re-entering the screen. Skipped if the entity died
|
||||
/// (remote delete) — mapping a dead @Model traps.
|
||||
private func absorbExternalUpdate() {
|
||||
doc = WorkoutDocument(from: workout)
|
||||
if let fresh = WorkoutDocument(fromLive: workout) { doc = fresh }
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
||||
Reference in New Issue
Block a user