Simple master screen with list, NavigationLink to editable detail view.
I want edits on the detail screen to update to the master list "cars" variable and the list UI.
- On the detail view, if I edit one field and exit the field, the value reverts to the original value. Why?
- If I edit one field, don't change focus and hit the back button. The master list updates. This is what I want, but I can only update 1 field because of problem #1. Should be able to edit all the fields.
- If I implement the == func in the Car struct, then no updates get saved. Why?
struct Car: Hashable, Equatable { var id: UUID = UUID() var make: String var model: String var year: Int // static func == (lhs: Car, rhs: Car) -> Bool { // return lhs.id == rhs.id // } } struct ContentView: View { @State private var cars: [Car] init() { cars = [ Car(make: "Toyota", model: "Camry", year: 2020), Car(make: "Honda", model: "Civic", year: 2021), Car(make: "Ford", model: "Mustang", year: 2022), Car(make: "Chevrolet", model: "Malibu", year: 2023), Car(make: "Nissan", model: "Altima", year: 2024), Car(make: "Kia", model: "Soul", year: 2025), Car(make: "Volkswagen", model: "Jetta", year: 2026) ] } var body: some View { NavigationStack { VStack { ForEach($cars, id: \.self) { $car in NavigationLink(destination: CarDetailView(car: $car)){ Text(car.make) } } } } } } struct CarDetailView: View { @Binding var car: Car var body: some View { Form { TextField("Make", text: $car.make) TextField("Model", text: $car.model) TextField("Year", value: $car.year, format: .number) } } }
- the short answer is because the
id
of the view in yourForEach
is\.self
(line 31). If you just write
ForEach($cars) { $car in
your code will work.
-
(with the code you posted) you can edit all the fields, but you won't see your changes in the detail view until you close the view by going Back, then opening a new CarDetailView.
-
the equality function is used to check if a structure has changed. If you make the equality function only dependent on the
id,
and have no means to changeid,
then when you edit your Car, the new struct is considered equal to the old struct value and your 'new' struct won't be saved to the cars array.
I have to admit I spent a lot of time today trying to understand why there's a difference between
ForEach($cars, id: \.self) { $car in
and
ForEach($cars) { $car in
but could not find a satisfactory explanation.
In fact, your code worked in the simulator for me, but not on a real phone, and not in Xcode's live preview. On the phone, it did accept edits, but the values propagated to the cars array were different, while in the live preview, I saw the behavior you described.
The id
used in the ForEach needs to be stable - self
keeps changing if you edit the fields.