You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 03:42:04