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.
There is a new property wrapper called @AppStorage for this use case, you may want to check it out here:
struct ContentView: View {
@AppStorage("AppLock") private var appLock = false
var body: some View {
...
Toggle("App Lock", isOn: $appLock)
}
}
Updated: In case you want to make it a class for passing-around purposes, you can try this approach. Notice objectWillChange.send()
means that whenever isAppLockEnabled
changes, it will notify any subscribed views that need to be refreshed.
final class AppSecurityStore: ObservableObject {
static let shared = AppSecurityStore()
private init() { }
var isAppLockEnabled: Bool {
get {
UserDefaults.standard.bool(forKey: "AppLock")
}
set {
UserDefaults.standard.setValue(newValue, forKey: "AppLock")
objectWillChange.send()
}
}
}
AppSecurityStore
need to be a @StateObject too, check this document.
struct ContentView: View {
@StateObject private var appSecurityStore: AppSecurityStore = .shared
...
}