I have a question regarding the following SwiftUI setup using @Model
.
I have a parent view which queries the model, extracts the first element, and passes that to child views.
My issue is that when I make changes to properties marked as @Transient
in the model, the child views do not re-render.
Parent
struct ParentView: View {
@Query private var myData: [MyData]
var body: some View {
if let data = myData.first {
TabView {
Overview(data: data)
Details(data: data)
}
.tabViewStyle(.verticalPage(transitionStyle: .identity))
} else {
ContentUnavailableView {
Label {
Text(verbatim: "Failed to load app content")
} icon: {
Image(systemName: "xmark")
}
}
}
}
}
Child
struct ChildView: View {
var data: WaterData
var body: some View {
Text("\(data.progress)")
}
}
If I query the model in the child view directly, then changes correctly propagate to the child view.
What am I doing wrong? Is there a property with which I can mark the var data
in the child view to let SwiftUI know it should observe changes?
The underlying data in the model is marked @Transient
because the source of truth is synched from Apple Health:
@Transient public var samples: [HKQuantitySample] = []
I should also note that the child view renders based on computed properties, such as:
public var progress: Double {
let todaysRecords = samples.filter {
Calendar.autoupdatingCurrent.isDateInToday($0.endDate)
}
let sum = todaysRecords.reduce(0, { sum, record in
sum + record.quantity.doubleValue(for: .literUnit(with: .milli))
})
return sum
}
Apologies for the messy post. I'm not sure which part of this setup breaks the UI updates. I could imagine having a transient property and using computed vars in the UI prevent SwiftUI from knowing about the changes. On the other hand, if I do the @Query
inside the child view, it works, despite the transient prop and computer vars.