SwiftUI - Binding var updates the original value only the first time, and then it doesn't update anymore

Viewed 50

I have a Picker that updates a @Binding value, that is linked to the original @State value. The problem is that it gets updated only the first time I change it, and then it always remains like that. Not only in the sheet, but also in the ContentView, which is the original view in which the @State variable is declared. Here's a video showing the problem, and here's the code:

ContentView:

struct ContentView: View {
    
    @State var cityForTheView = lisbon
    @State var showCitySelection = false

    var body: some View {
        VStack {
            //View
        }
        .sheet(isPresented: $showCitySelection) {
            MapView(cityFromCV: $cityForTheView)
        }
    }
}

MapView:

struct MapView: View {
    
    @Environment(\.presentationMode) var presentationMode
    @Binding var cityFromCV : CityModel
    
    @State var availableCities = [String]()
    @State var selectedCity = "Lisbon"
    
    var body: some View {
        NavigationView {
            ZStack {
            VStack {
                Form {
                    HStack {
                        Text("Select a city:")
                        Spacer()
                        Picker("", selection: $selectedCity) {
                            ForEach(availableCities, id: \.self) {
                                            Text($0)
                                        }
                                    }
                        .accentColor(.purple)

                    }
                    .pickerStyle(MenuPickerStyle())
                    

                    Section {
                        Text("Current city: \(cityFromCV.cityName)")
                    }
                }
            }
        }
        }
        .interactiveDismissDisabled()
        .onAppear {
            availableCities = []
            for ct in cities {
                availableCities.append(ct.cityName)
            }
        }
        .onChange(of: selectedCity) { newv in
            self.cityFromCV = cities.first(where: { $0.cityName == newv })!
        }
    }
}

CityModel:

class CityModel : Identifiable, Equatable, ObservableObject, Comparable {
    
    var id = UUID()
    var cityName : String
    var country : String
    var imageName : String

    init(cityName: String, country: String, imageName : String) {
        self.cityName = cityName
        self.country = country
        self.imageName = imageName
    }
    
    static func == (lhs: CityModel, rhs: CityModel) -> Bool {
        true
    }
    
    static func < (lhs: CityModel, rhs: CityModel) -> Bool {
        true
    }

}
  
var cities = [
    lisbon,
    CityModel(cityName: "Madrid", country: "Spain", imageName: "Madrid"),
    CityModel(cityName: "Barcelona", country: "Spain", imageName: "Barcelona"),
    CityModel(cityName: "Paris", country: "France", imageName: "Paris")
]

var lisbon = CityModel(cityName: "Lisbon", country: "Portugal", imageName: "Lisbon")

What am I doing wrong?

1 Answers

The problem are:

at line 35: you use selectedCity to store the selected data from your picker.

 Picker("", selection: $selectedCity) {

then at your line 46: you use cityFromCV.cityName to display the data which will always show the wrong data because you store your selected data in the variable selectedCity.

 Section {
  Text("Current city: \(cityFromCV.cityName)")
 }

Solution: Just change from cityFromCV.cityName to selectedCity.

Related