-1

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?

2
  • If you need to edit some property of an Item, then just pass that property. If you need to pass an Item, then use @Bindable if you need it in a function that takes a binding eg, TextField(...), otherwise just a let. Since items is already observable do not use @ObservableObject. Try reading the docs: developer.apple.com/documentation/swiftdata/… Commented Jul 22 at 1:29
  • Normally you would only pass the properties each view needs not the whole object. Commented Jul 22 at 7:00

1 Answer 1

1

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)
    }
}

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.