2

I used user defaults to save the values from a form. I wish to pass one of those values ("nationality") to another view.

I tried using the view model in order to do so, but I get an empty value in the text where I wish to pass this data.

first here is a look at the form

import SwiftUI

struct ProfilePageView: View {
    @ObservedObject var viewModel = ViewModel()
    
    var body: some View {
        Form {
            Section(header: Text("Personal Ifo")) {
                TextField("User Name", text: $viewModel.userName)
                
            }
            //
            Section(header: Text("Your Nationality")) {
                Picker(selection: $viewModel.nationality, label: Text("You were born in")) {
                    ForEach(viewModel.nationalities, id: \.self) { nationality in
                        Text(nationality)
                    }
                    
                }
            } //nationality section end
            //
            Section(header: Text("Country of residence")) {
                Picker(selection: $viewModel.countryOfResidence, label: Text("Where do you live ?")) {
                    ForEach(viewModel.countriesOfResidence, id: \.self) { residence in
                        Text(residence)
                    }
                }
            } // country of residence section end
            //
            
        }
        .navigationTitle("Profile")
        //form end
        
    }
}

second here is my view model, which enables me to save the form values to user default

import Foundation

class ViewModel: ObservableObject {
    @Published var userName: String {
        didSet {
            UserDefaults.standard.setValue(userName, forKey: "username")
        }
    }
    //nationality
    @Published var nationality: String {
        
        didSet {
            UserDefaults.standard.setValue(nationality, forKey: "nationality")
        }

    }
    public var nationalities = ["USA", "Japan", "Senegal", "France"]
    
    //country of residence
    @Published var countryOfResidence: String {
        didSet {
            UserDefaults.standard.setValue(countryOfResidence, forKey: "country of residence")
        }
    }
    public var countriesOfResidence = ["USA", "Japan", "Senegal", "France"]
    
    init() {
        self.userName = UserDefaults.standard.object(forKey: "username") as? String ?? ""
        self.nationality = UserDefaults.standard.object(forKey: "nationality") as? String ?? ""
        self.countryOfResidence = UserDefaults.standard.object(forKey: "Coutry of residence") as? String ?? ""
    }
}

finally here is the view where I wish to attach this value. I am using @observedObject in order to try an retrieve the "nationality" value from my view model. however the value is not passed in the text

import SwiftUI

struct VisaPolicyDetailView: View {
    
    @Binding var country: Country
    @ObservedObject var viewmodel = ViewModel()
    
    var body: some View {
        VStack(alignment: .leading,spacing: 20) {
            //a dismiss button
            HStack {
                Spacer()
                Image(systemName: "xmark")
                    .renderingMode(.original)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 40, height: 40)
            }
            
            Spacer()
            
            Text(country.countryName)
                .font(.title)
                .fontWeight(.medium)
            Text("Visa policy for \(viewmodel.nationality) : visa policy")
                .font(.title2)
            
            Spacer()
        }
        .padding()
        .navigationTitle("Visa Policy Detail")
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209
LEKYSMA
  • 141
  • 10

1 Answers1

1

In the provided scenario it is better to use shared ViewModel, like

class ViewModel: ObservableObject {
   static let shared = ViewModel()

   // .. other code
}

and use that shared in all affected views

struct ProfilePageView: View {
    @ObservedObject var viewModel = ViewModel.shared  // << here !!
...

and

struct VisaPolicyDetailView: View {
    
    @Binding var country: Country
    @ObservedObject var viewmodel = ViewModel.shared  // << here !!
...

then both views will observe same instance of ViewModel.

SwiftUI 2.0: use AppStorage to automatically store/observe user defaults, like

@AppStorage("nationality") var nationality = "some default here"
Asperi
  • 228,894
  • 20
  • 464
  • 690