I have created a singleton class called AppSecurityStore
which currently only holds a boolean property to store a setting value.
final class AppSecurityStore {
static let shared = AppSecurityStore()
private init() { }
var isAppLockEnabled: Bool {
get {
UserDefaults.standard.bool(forKey: "AppLock")
}
set {
UserDefaults.standard.setValue(newValue, forKey: "AppLock")
}
}
}
I have a view where I toggle the value for this property.
struct ContentView: View {
@State private var appSecurityStore: AppSecurityStore
init(appSecurityStore: AppSecurityStore) {
self.appSecurityStore = appSecurityStore
}
var body: some View {
Form {
Section {
Toggle("App Lock", isOn: $appSecurityStore.isAppLockEnabled)
}
}
}
}
If I change the toggle value, it does get saved in User Defaults properly. However if I background the app and bring it back to the foreground, it doesn’t reflect the updated state. It still shows the previous value!
The appSecurityStore
variable inside the view is a @State
variable so I’m not sure why it doesn’t persist the updated value.
Any help to resolve this is appreciated.
I have uploaded a demo project here.
Important: I cannot use environment objects in this app due to decisions being made to not use them since they don’t play well with MVVM.
2
Answers
you need to observe the changes, for the moment you pass a copy of the AppSecurityStore not a refference.
conform to ObservableObject and use the @Publish:
update:
initiate the IsAppLock in init and use the didSet to update the changes
There is a new property wrapper called @AppStorage for this use case, you may want to check it out here:
Updated: In case you want to make it a class for passing-around purposes, you can try this approach. Notice
objectWillChange.send()
means that wheneverisAppLockEnabled
changes, it will notify any subscribed views that need to be refreshed.AppSecurityStore
need to be a @StateObject too, check this document.