Search code examples
iosswiftswiftuiswiftdata

SwiftData list bindings with @Query


Since Swift 5.5 we could create SwiftUI lists with bindings like this (e.g. see this answer):

class Item {
    // ...
    var isOn: Bool
}

struct ContentView: View {
    @State private var items: [Item] = []
    var body: some View {
        NavigationView {
            List {
                ForEach($items) { $item in     // <--- list binding
                    Toggle(isOn: $item.isOn) {
                        Text("Vibrate on Ring")
                    }
                }
            }
        }
    }
}

Now I want to do something similar with SwiftData but I get an error:

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var items: [Item]
    var body: some View {
        NavigationView {
            List {
                ForEach($items) { $item in //   <--- Cannot find '$items' in scope
    // ...

How can I render a list of SwiftData objects that allows inline editing of objects through bindings?


Solution

  • You can utilize the new Bindable, which has a subscript operator to wrap the underlying data into a binding variable:

    ForEach(items) { item in
        Toggle(isOn: Bindable(item).isOn) { ... }
    }
    

    If the binding need to be reused multiple times, you can also create the Bindable object within the view:

    ForEach(items) { item in
        @Bindable var item = item
        Toggle(isOn: $item.isOn) { ... }
    }
    

    Note the usage of $, since the bindable object is created as a property wrapper.