Xcode中onChange监听Preferences对象变更未触发问题求助
问题排查:onChange监听Preferences实例未触发的原因
问题场景
我自定义了遵循ObservableObject与Equatable协议的Preferences类:
class Preferences: ObservableObject, Equatable{ static func == (lhs: Preferences, rhs: Preferences) -> Bool { return lhs.email == rhs.email && lhs.password == rhs.password && lhs.faceID == rhs.faceID && lhs.currency == rhs.currency && lhs.colourScheme == rhs.colourScheme && lhs.appTheme == rhs.appTheme } @Published var email: String = "" @Published var password: String = "" @Published var faceID: Bool = false @Published var currency: Currencies = .EUR @Published var colourScheme: ColourScheme = .system @Published var appTheme: Theme = .orange }
将该类实例作为ViewModel的@Published属性存储:
class ViewModel: ObservableObject { @Published var preferences = Preferences() }
使用onChange监听其变更,期望触发updateSettings函数,但该监听从未被调用:
.onChange(of: viewModel.preferences){ newValue in viewModel.updateSettings(faceID: viewModel.preferences.faceID, currency: viewModel.preferences.currency, colourScheme: viewModel.preferences.colourScheme, appTheme: viewModel.preferences.appTheme) }
根本原因
@Published修饰的是Preferences实例的引用,只有当这个引用发生变化(比如重新赋值一个全新的Preferences()对象)时,才会触发外层的onChange。而你实际修改的是实例内部的@Published属性(如faceID、currency),这种操作只会让Preferences自身的objectWillChange发送通知,但不会改变ViewModel中preferences的引用地址,因此外层的onChange不会被触发。
解决方案
方案1:直接监听内部具体属性
如果只关心部分属性的变化,可以单独监听这些属性,或者组合监听多个属性:
// 方式1:单独监听每个属性 .onChange(of: viewModel.preferences.faceID) { _ in viewModel.updateSettings(faceID: viewModel.preferences.faceID, currency: viewModel.preferences.currency, colourScheme: viewModel.preferences.colourScheme, appTheme: viewModel.preferences.appTheme) } .onChange(of: viewModel.preferences.currency) { _ in viewModel.updateSettings(faceID: viewModel.preferences.faceID, currency: viewModel.preferences.currency, colourScheme: viewModel.preferences.colourScheme, appTheme: viewModel.preferences.appTheme) } // 方式2:组合监听多个属性 .onChange(of: [viewModel.preferences.faceID, viewModel.preferences.currency, viewModel.preferences.colourScheme, viewModel.preferences.appTheme]) { _ in viewModel.updateSettings(faceID: viewModel.preferences.faceID, currency: viewModel.preferences.currency, colourScheme: viewModel.preferences.colourScheme, appTheme: viewModel.preferences.appTheme) }
方案2:在ViewModel内部监听变化
将逻辑统一放在ViewModel中,订阅preferences的objectWillChange通知,内部属性变化时自动触发更新:
class ViewModel: ObservableObject { @Published var preferences = Preferences() private var cancellables = Set<AnyCancellable>() init() { preferences.objectWillChange .sink { [weak self] _ in guard let self = self else { return } self.updateSettings(faceID: self.preferences.faceID, currency: self.preferences.currency, colourScheme: self.preferences.colourScheme, appTheme: self.preferences.appTheme) } .store(in: &cancellables) } func updateSettings(faceID: Bool, currency: Currencies, colourScheme: ColourScheme, appTheme: Theme) { // 你的业务逻辑代码 } }
这种方式不需要在View层编写onChange,逻辑更集中。
内容的提问来源于stack exchange,提问作者Cian B
相关产品推荐
相关产品推荐

