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

SwiftUI:如何检测ObservableObject数组中@Published变量的变更

解决方案:Toggle列表的修改状态判断与保存处理

一、判断用户是否修改Toggle,控制Save按钮启用/禁用

核心思路是对比每个Model的当前选择状态与初始状态,只要有一个Model状态变化,就启用Save按钮。具体实现步骤:

  1. 给Model添加初始状态记录:新增originalIsSelected属性保存初始选择值,用于后续对比是否修改。
  2. ViewModel监听状态变化:监听每个Model的isSelected属性变动,实时计算是否存在修改,并通过@Published变量同步给View。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 16:45:36