I am utilising SwfitUI's new @AppStorage property. However, the willSet property observer is not firing.
Here is my UserDefaults value codeResult changing from an asynchronous call:
class Main: ObservableObject {
func code(data: [AnyHashable:Any?]){
UserDefaults.standard.set("incorrect", forKey: "codeResult")
}
}
And below in my View, willSet is not being called:
struct MainView: View {
@ObservedObject var main = Main()
@ObservedObject var mainCountdown: CountDown
@ObservedObject var locationManager = LocationManager()
@State private var keyboardHeight: CGFloat = 0
@State var showCode: Bool = false
@AppStorage("codeResult") var codeResult = UserDefaults.standard.string(forKey: "codeResult") ?? "" {
willSet {
print("willSet: \(newValue)") // doesn't fire
}
didSet {
print("didSet: \(oldValue)") // doesn't fire
}
}
Any idea why it's not firing?
The willSet/didSet are observers for property change (not publisher observers). Thus to get into willSet/didSet you have to change property codeResult directly.
Here is a demo that depicts differences - both buttons update Text (because codeResult is dynamic observable property, but only direct assign to codeResult activates property willSet/didSet)
Tested with Xcode 12b3 / iOS 14.
struct DemoAppStorageDidSet: View {
@AppStorage("codeResult") var codeResult: String = "Default" { // << default value
willSet {
print("willSet: \(newValue)")
}
didSet {
print("didSet: \(oldValue)")
}
}
var body: some View {
VStack {
Text("Code Result: \(codeResult)")
Divider()
Button("AppStore Update") {
self.codeResult = "AppStore" // << activates willSet/didSet !!
}
Divider()
Button("UserDefaults Update") {
UserDefaults.standard.set("UserDefaults", forKey: "codeResult")
}
}
}
}
Note: you don't need to initialise AppStorage with UserDefaults value, it is read by default.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With