SwiftUI:如何检测ObservableObject数组中@Published变量的变更
解决方案:Toggle列表的修改状态判断与保存处理
一、判断用户是否修改Toggle,控制Save按钮启用/禁用
核心思路是对比每个Model的当前选择状态与初始状态,只要有一个Model状态变化,就启用Save按钮。具体实现步骤:
- 给Model添加初始状态记录:新增
originalIsSelected属性保存初始选择值,用于后续对比是否修改。 - ViewModel监听状态变化:监听每个Model的
isSelected属性变动,实时计算是否存在修改,并通过@Published变量同步给View。 - View绑定按钮状态:根据ViewModel的修改标记,启用或禁用Save按钮。
修改后的Model类
class Model: ObservableObject, Hashable { var id: String @Published var isSelected: Bool var originalIsSelected: Bool // 记录初始选择状态 init(id: String, isSelected: Bool) { self.id = id self.isSelected = isSelected self.originalIsSelected = isSelected } // 实现Hashable协议必要方法 static func == (lhs: Model, rhs: Model) -> Bool { lhs.id == rhs.id } func hash(into hasher: inout Hasher) { hasher.combine(id) } }
修改后的ViewModel类(核心逻辑)
import Combine class ViewModel: ObservableObject { @Published var list: [Model] @Published var hasChanges = false // 标记是否有修改 private var cancellables = Set<AnyCancellable>() init() { // 示例初始化数据,按需替换 self.list = [ Model(id: "Item1", isSelected: false), Model(id: "Item2", isSelected: true), Model(id: "Item3", isSelected: false) ] setupModelListeners() } // 监听每个Model的isSelected变化,更新修改状态 private func setupModelListeners() { list.forEach { model in model.$isSelected .sink { [weak self] _ in self?.updateHasChanges() } .store(in: &cancellables) } } // 计算是否存在修改的Model private func updateHasChanges() { hasChanges = list.contains { $0.isSelected != $0.originalIsSelected } } }
View中控制按钮状态
struct MyView: View { @ObservedObject var viewModel: ViewModel var body: some View { VStack { ForEach(viewModel.list, id: \.self) { model in Toggle(model.id, isOn: $model.isSelected) } Button("Done") { viewModel.save() } .disabled(!viewModel.hasChanges) // 无修改时禁用按钮 Button("Clear") { viewModel.clear() } } .padding() } }
二、点击Save时列出所有被修改的Model
在ViewModel的save方法中,过滤出isSelected与originalIsSelected不一致的Model即可获取修改项。保存完成后,需要更新初始状态为当前值,并重置修改标记。
ViewModel的save方法实现
func save() { // 过滤所有状态被修改的Model let modifiedModels = list.filter { $0.isSelected != $0.originalIsSelected } // 输出修改内容(实际项目中替换为存储/上传逻辑) print("已修改的项目:") modifiedModels.forEach { model in print("ID: \(model.id) | 原状态: \(model.originalIsSelected) | 新状态: \(model.isSelected)") } // 保存完成后更新初始状态,重置修改标记 list.forEach { $0.originalIsSelected = $0.isSelected } hasChanges = false }
完善Clear方法
点击Clear时将所有Toggle重置为初始状态:
func clear() { list.forEach { $0.isSelected = $0.originalIsSelected } hasChanges = false }
内容的提问来源于stack exchange,提问作者pradeep
相关产品推荐
相关产品推荐

