Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

SwiftUI: UserDefaults Binding

I have a settings view that has a button which toggles a binding that’s stored with UserDefaults.

struct Settings: View {
    @ObservedObject var settingsVM = SetttingsViewModel()

    var body: some View {
        if settingsVM.settingActivated {
            Text("Setting activated")
        } else {
            Text("Setting deactivated")
        }
        
        Button("Activate") {
            settingsVM.settingActivated.toggle()
        }
        

    }
    
}

SettingsViewModel

class SetttingsViewModel: ObservableObject {
    
    @Published  var settingActivated: Bool = UserDefaults.standard.bool(forKey: "settingActivated") {
    didSet {
        UserDefaults.standard.set(self.settingActivated, forKey: "settingActivated")
      }
    }
    
}

The text("Setting activated/ Setting deactivated")in the Settings view update instantly when i press the button but the text in ContentView doesn’t change unless i restart the app & i have no idea why.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

struct ContentView: View {
    @ObservedObject var settingsVM = SetttingsViewModel()
    @State private var showsettings = false
    var body: some View {
        
        if settingsVM.settingActivated {
            
            Text("Setting Activated")
                .padding(.top)
        } else {
            Text("Setting Deactivated")
                .padding(.top)
        }
            Button("Show Settings") {
                showsettings.toggle()
                
            }
            .sheet(isPresented: $showsettings) {
                Settings()
                   }
            .frame(width: 300, height: 300)
       }
    }

This is for a macOS 10.15 app so i can’t use @AppStorage

>Solution :

Right now, you don’t have any code in you view model to react to a change in UserDefaults. Meaning, if UserDefaults gets a new value set, it won’t know about it. And, since you’re using a different instance of SettingsViewModel in your two different views, they can easily become out-of-sync.

The easiest change would be to pass the same instance of SettingsViewModel to Settings:

struct Settings: View {
    @ObservedObject var settingsVM: SettingsViewModel //<-- Here

    var body: some View {
        if settingsVM.settingActivated {
            Text("Setting activated")
        } else {
            Text("Setting deactivated")
        }
        
        Button("Activate") {
            settingsVM.settingActivated.toggle()
        }
    }
}

struct ContentView: View {
    @ObservedObject var settingsVM = SetttingsViewModel()
    @State private var showsettings = false
    var body: some View {
        
        if settingsVM.settingActivated {
            
            Text("Setting Activated")
                .padding(.top)
        } else {
            Text("Setting Deactivated")
                .padding(.top)
        }
            Button("Show Settings") {
                showsettings.toggle()
                
            }
            .sheet(isPresented: $showsettings) {
                Settings(settingsVM: settingsVM) //<-- Here
            }
            .frame(width: 300, height: 300)
       }
    }

Another option would be to use a custom property wrapper (like AppStorage, but available to earlier targets): https://xavierlowmiller.github.io/blog/2020/09/04/iOS-13-AppStorage


Also, @vadian’s comment is important — if you had access to it, you’d want to use @StateObject. But, since you don’t, it’s important to store your ObservableObject at the top level so it doesn’t get recreated.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading