SwiftUI中@AppStorage的willSet属性观察者未触发问题咨询
问题原因分析
这是个很常见的@AppStorage使用误区,我来帮你拆解核心原因:@AppStorage的属性观察者(willSet/didSet)只有在直接通过属性本身赋值时才会触发,而你当前是通过UserDefaults.standard.set()直接修改存储的值,这个操作会绕过@AppStorage属性的setter方法,导致观察者完全无法被调用。
具体说:
@AppStorage是一个属性包装器,它底层和UserDefaults绑定,当你直接给codeResult赋值时,包装器会同步更新UserDefaults并触发属性观察者。- 但如果直接调用
UserDefaults.standard.set(),虽然@AppStorage会同步更新属性的底层值,但这个更新是通过监听UserDefaults系统通知实现的,并没有走属性的setter逻辑,所以willSet和didSet自然不会被触发。
解决方案
有两种实用的解决思路,你可以根据自己的场景选择:
方案一:直接通过@AppStorage属性赋值(推荐)
修改你的Main类,让它通过@AppStorage属性来修改值,彻底避免直接操作UserDefaults:
class Main: ObservableObject { // 用@AppStorage直接绑定codeResult @AppStorage("codeResult") var codeResult = "" func code(data: [AnyHashable:Any?]){ // 直接给属性赋值,会自动触发willSet/didSet并同步到UserDefaults codeResult = "incorrect" } }
然后在MainView中,移除自己的@AppStorage声明,直接使用main实例的codeResult即可:
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 var body: some View { // 示例:使用main的codeResult Text(main.codeResult) // 你的其他视图内容 } }
这样修改后,当main.code()被调用时,直接赋值会同时触发属性观察者和UI更新,完全符合@AppStorage的设计初衷。
方案二:监听UserDefaults变更通知(适用于必须直接操作UserDefaults的场景)
如果因为业务限制必须直接调用UserDefaults.standard.set(),你可以通过监听系统通知来替代willSet/didSet的逻辑:
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") ?? "" var body: some View { // 你的视图内容 Text(codeResult) .onAppear { // 监听UserDefaults的变更通知 NotificationCenter.default.addObserver( forName: UserDefaults.didChangeNotification, object: nil, queue: .main ) { _ in // 这里处理原来willSet/didSet中的逻辑 print("codeResult updated: \(codeResult)") } } .onDisappear { // 记得移除观察者,避免内存泄漏 NotificationCenter.default.removeObserver(self) } } }
总结
优先选择方案一,这是@AppStorage的设计本意:通过属性赋值统一管理状态和存储,既能保证UI自动更新,也能正常触发属性观察者。
内容的提问来源于stack exchange,提问作者Zorgan
相关产品推荐
相关产品推荐

