So I'm building a relatively simple app using all the latest iOS 17 SwiftUI and Swift Data. I'm trying to follow Apple sample code and the "Model View" pattern (which I find pretty helpful Building Large Scale Apps Swiftui | AzamSharp )
It's not clear to me what is the right way to share data between child views, as they don't update as I would expect. I would think that using an object with @Model which of course also gives it @Observable that putting more logic in those to update Views would be the elegant solution, but the Views don't always update as I would expect. (like if you had a @State and a @Binding)
So below is my example code, and here are some questions I have that I haven't found clear answers to. (I apologize this is quite long, but I wasn't sure how else to ask, I'm looking for deeper understanding not just a "make it work" but rather learning best practices.)
-
when I pass my
@Modelobject, in this caseJacketfrom one view to another, is it creating a copy or is it a shared reference? I thought since its a class its shared, so if I make a change on one it affects the other, however my views don't seem to behave that way. e.g. what is my source of truth? -
is this the right way to share logic between views, just using the
@Modelobject for it all? I thought since it had@Observablethis would be the most elegant solution. However, maybe I should create a@Stateor@StateObjectseparately (a viewModel, coordinator etc.) and take that logic out of myJacket @Model? -
If I mark
Jacket@Bindableto toggle state (like a modal), it does not happen right away, only when the view is dismissed and reloaded, is this a problem with needing the main thread and@MainActoror something else? -
In my content view, the detail view
Jacketis coming from aletfrom the selection ID on the array of Jackets. (this is how some Apple code demonstrated it with SwiftData Queries) However, am I losing the ability for them to share state this way? Apple elsewhere recommended selection being the type of the object itself. And in that case, should it then be a@Bindable vareven if I don't have bindings but want children to update parents and vice versa?
import SwiftUI
import SwiftData
struct Sample: View {
@Query private var jackets: [Jacket]
@Environment(NavigationModel.self) private var navModel
var body: some View {
NavigationSplitView {
@Bindable var navModel = navModel
List(jackets, selection: $navModel.selectedId) { jacket in
JacketRow(jacket: jacket)
}
} detail: {
if let jacket = jackets[navModel.selectedId] {
JacketDetail(jacket: jacket)
} else {
ContentUnavailableView("Nothing selected", systemImage: "filemenu.and.selection")
}
}
}
}
struct JacketDetail: View {
var jacket: Jacket
var body: some View {
VStack {
Text(jacket.title)
.font(.title)
JacketChildDetail(jacket: jacket)
.padding()
}
}
}
struct JacketChildDetail: View {
var jacket: Jacket
var body: some View {
if jacket.frontImageData {
// some view
} else {
// some other view
}
}
}