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

如何合并ObservableObject多次变更,仅发送一次objectWillChange通知?

在Swift中将ObservableObject的多次属性变更合并为单次发布通知

我有一个包含@Published可变变量的ObservableObject类,在某个函数中会多次修改该类的属性值。现在需要将这些分散的变更合并为一个事务,让objectWillChange发布者仅发送一次通知,避免多次触发更新。

示例代码

struct MyDataModel {
    var t1: String = ""
    var t2: String = ""
    var t3: String = ""
}

class MyOO: ObservableObject {
    @Published var data: MyDataModel = MyDataModel()
    
    func mutateData() { // 在此方法中合并所有变更
        data.t1 = "1"
        data.t2 = "12"
        data.t3 = "123"
    }
}

let myoo = MyOO()
_ = myoo.objectWillChange.sink { print(myoo.data) }

myoo.mutateData()

当前输出

MyDataModel(t1: "", t2: "", t3: "")
MyDataModel(t1: "1", t2: "", t3: "")
MyDataModel(t1: "1", t2: "12", t3: "")

期望输出

MyDataModel(t1: "1", t2: "12", t3: "")

直接复制@Published变量的值、修改后再赋值回去的方法需要大量代码改动,希望找到更简洁、符合Swift习惯的实现方式。


解决方案

方法1:手动控制objectWillChange发送时机

在批量修改前手动发送一次objectWillChange通知,后续修改结构体属性时,@Published的自动通知会被抑制,所有变更合并为一次发布:

func mutateData() {
    objectWillChange.send()
    data.t1 = "1"
    data.t2 = "12"
    data.t3 = "123"
}

方法2:自定义withTransaction扩展(推荐)

给ObservableObject添加通用扩展,封装事务逻辑,让批量修改代码更整洁且复用性强:

extension ObservableObject {
    func withTransaction(_ block: () -> Void) {
        objectWillChange.send()
        block()
    }
}

使用时将所有变更包裹在闭包中:

func mutateData() {
    withTransaction {
        data.t1 = "1"
        data.t2 = "12"
        data.t3 = "123"
    }
}

方法3:直接生成新结构体实例赋值

利用结构体的值类型特性,一次性生成修改后的新实例赋值给@Published变量,自然只会触发一次通知:

func mutateData() {
    data = MyDataModel(t1: "1", t2: "12", t3: "123")
}

如果结构体属性较多,可通过复制语法保留原有属性值:

func mutateData() {
    data = MyDataModel(
        t1: "1",
        t2: "12",
        t3: "123",
        t4: data.t4 // 保留原有属性值
    )
}

内容的提问来源于stack exchange,提问作者Aswath

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 03:43:29