Home > front end >  Binding to subscript doesn't update TextField (macOS)
Binding to subscript doesn't update TextField (macOS)

Time:04-11

I have this Store struct, which is a wrapper for all my data. It has a subscript operator which takes in a UUID, and returns the associated object.

This way, I can have a List bind to a selection variable, which has type UUID, and then in another view I can access the selected object from that UUID.

However, I'm experiencing an issue where my TextField which binds to the Store doesn't update. It does update if I wrap it in another Binding, or if I instead just use Text.

Here is an minimal reproducible example:

struct Person: Identifiable, Hashable {
    let id = UUID()
    var name: String
}

struct Store {
    var data: [Person]
    
    subscript(id: Person.ID) -> Person {
        get {
            data.first(where: { $0.id == id })!
        }
        set {
            data[data.firstIndex(where: { $0.id == id })!] = newValue
        }
    }
}

struct ContentView: View {
    @State var store = Store(data: [
        Person(name: "Joe"),
        Person(name: "Eva"),
        Person(name: "Sam"),
        Person(name: "Mary")
    ])
    @State var selection: Person.ID?
    
    var body: some View {
        NavigationView {
            List(store.data, selection: $selection) {
                Text($0.name)
            }
            
            if let selection = selection {
                // Creating a new Binding which simply wraps $store[selection].name
                // fixes this issue. Or just using Text also works.
                TextField("Placeholder", text: $store[selection].name)
            }
            else {
                Text("No Selection")
            }
        }
    }
}

To reproduce this issue, just click different names on the Sidebar. For some reason the detail view's TextField doesn't update!

This issue can also be resolved if we simply move the Store to a ObservableObject class with @Published.

Also, making the Store conform to Hashable doesn't help this issue.

I feel like I'm missing something very basic with SwiftUI. Is there any way to fix this?

CodePudding user response:

try this:

TextField("Placeholder", text: $store[selection].name)
    .id(selection)  // <-- here
  • Related