Search code examples
swiftformspickercombine

persistent value in a picker changing views in SwiftUI


I don't understand how implementing in SwiftUI a simple picker showing a list of values that retain the selected value switching between different views. I'm able to use the selected value to update the Model via Combine framework by the way.

here's the code, but the onAppear{}/onDisappear{} doesn't work as expected:

struct CompanyView: View {

    @ObservedObject var dataManager: DataManager = DataManager.shared

    @State var selTipoAzienda = 0

    var body: some View {
        VStack {
            companyPhoto
            Text("Company view")
            Form {
                Picker(selection: $selTipoAzienda, label: Text("Tipo Azienda")) {
                    ForEach(0 ..<  self.dataManager.company.tipoAziendaList.count) {
                        Text(self.dataManager.company.tipoAziendaList[$0])
                    }
                }
            }

            Button(action:  {self.dataManager.cambiaTipoAzienda(tipoAzienda: self.dataManager.company.tipoAziendaList[self.selTipoAzienda]) }) {
                Image(systemName: "info.circle.fill")
                    .font(Font.system(size: 28))
                    .padding(.horizontal, 16)
            }
        }
//        .onAppear{
//            self.selTipoAzienda = self.dataManager.company.tipoAziendaList.firstIndex(of: self.dataManager.company.tipoAzienda) ?? 0
//        }
//        .onDisappear{
//            self.dataManager.cambiaTipoAzienda(tipoAzienda: self.dataManager.company.tipoAziendaList[self.selTipoAzienda])
//        }
    }

I think binding and didSet would be the answer but I don't know how they have to be implemented


Solution

  • The provided code is not compilable/testable, so below just shows an approach (see also comments inline)

    struct CompanyView: View {
    
        @ObservedObject var dataManager: DataManager = DataManager.shared
        @State var selTipoAzienda: Int
    
        init() {
            // set up initial value from persistent data manager
            _selTipoAzienda = State(initialValue: self.dataManager.company.tipoAziendaList.firstIndex(of: self.dataManager.company.tipoAzienda) ?? 0)
        }
    
        var body: some View {
            // inline proxy binding to intercept Picker changes
            let boundSelTipoAzienda = Binding(get: { self.selTipoAzienda }, set: {
                self.selTipoAzienda = $0
    
                // store selected value into data manager
                self.dataManager.cambiaTipoAzienda(tipoAzienda: self.dataManager.company.tipoAziendaList[$0])
            })
    
            return VStack {
                companyPhoto
                Text("Company view")
                Form {
                    Picker(selection: boundSelTipoAzienda, label: Text("Tipo Azienda")) {
                        ForEach(0 ..<  self.dataManager.company.tipoAziendaList.count) {
                            Text(self.dataManager.company.tipoAziendaList[$0])
                        }
                    }
                }
    
                Button(action:  {self.dataManager.cambiaTipoAzienda(tipoAzienda: self.dataManager.company.tipoAziendaList[self.selTipoAzienda]) }) {
                    Image(systemName: "info.circle.fill")
                        .font(Font.system(size: 28))
                        .padding(.horizontal, 16)
                }
            }
        }
    }