I have a list of things (TestSettings
). I use the @State annotation. I drill down and can edit the items. In the drill-down, I use @Binding as I want it to change the original rather than a copy.
However, as soon as I edit the field in the second level, it pops back to the top level. For example, with the following code, I tap the top entry in the list and I see "A". Tap in the text box, add another "A" and it immediately pops back to the list. If I go back it has remembered the change ("AA").
What am I doing wrong?
struct TestSettings : Identifiable, Hashable {
var name : String
var id : String { self.name }
}
struct SecondLevel : View {
@Binding var things : TestSettings
var body : some View {
List {
TextField("Name", text: $things.name)
}
}
}
struct PickerTest: View {
@State var settings : [TestSettings]
var body: some View {
NavigationView {
List {
ForEach($settings, id: \.self) { thing in
NavigationLink(destination: SecondLevel(things: thing)) {
Text("X")
}
}
}
.navigationTitle("Test")
}
}
}
struct PickerTest_Previews: PreviewProvider {
static var previews: some View {
PickerTest(settings: [TestSettings(name: "A"), TestSettings(name: "B")])
}
}
You change thing
which is ID of ForEach
(by .self
), so once you changed it that thing actually disappeared (for List) and new one appeared, so List's content updated.
A possible solution is to have persistent (separated) id
of TestSettings
so editing it would not affect its identity.
Like next
struct TestSettings : Identifiable, Hashable {
var name : String
var id = UUID() // << here !!
}
// ...
// identifiable, os explicit key-path is not needed, `id` used by default
ForEach($settings) { thing in // << here !!
NavigationLink(destination: SecondLevel(things: thing)) {
Text("X")
}
}