Reputation: 9123
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?
Upvotes: 4
Views: 1611
Reputation: 9123
Adding onReceive()
to the view seemed to successfully track changes to codeResult
where I could execute code blocks:
.onReceive(self.codeResult.publisher.collect()) {_ in
if self.codeResult == CodeResult.incorrect.rawValue {
print("CHANGED TO INCORRECT")
self.showCode = false
}
}
Upvotes: 0
Reputation: 257749
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.
Upvotes: 2