I have a SwiftData class that I get with @Query private var items: [Item] in a SwiftUI view. Then I pass it to a sub view that passes it to other sub views. What is the best way to pass the class around. I need to be able to modify it, and its properties (structs and classes) in the sub views. Should I use @Binding, @Bindable, @ObservableObject or something else?
1 Answer
Here is an example of how to pass the items around to various subviews.
In essence, use a let items: [Item] in the subviews that just display the
info. Use a @Bindable var item: Item when you want to modify an item property.
Use @Environment(\.modelContext) private var modelContext to add (or delete)
an item to SwiftData, that will update your array items: [Item].
You cannot add or delete an item from the array items: [Item] directly
(it is read only), you must use the context.
@Model
final class Item {
var name: String
init(name: String) {
self.name = name
}
}
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: Item.self)
}
}
struct ContentView: View {
@Query private var items: [Item]
var body: some View {
Layer1View(items: items)
}
}
struct Layer1View: View {
let items: [Item]
var body: some View {
Text("Layer1View items count: \(items.count)")
Layer2View(items: items)
}
}
struct Layer2View: View {
@Environment(\.modelContext) private var modelContext
let items: [Item]
var body: some View {
List(items) { item in
EditorView(item: item)
}
Button("Add item") {
let newItem = Item(name: "Mickey Mouse")
modelContext.insert(newItem)
}
}
}
struct EditorView: View {
@Bindable var item: Item
var body: some View {
TextField("", text: $item.name).border(.red)
}
}
Item, then just pass that property. If you need to pass anItem, then use@Bindableif you need it in a function that takes a binding eg, TextField(...), otherwise just alet. Sinceitemsis alreadyobservabledo not use@ObservableObject. Try reading the docs: developer.apple.com/documentation/swiftdata/…