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

SwiftUI使用定时器更新Model后UI未同步刷新问题排查

问题根因

你的问题和定时器无关,核心是**Model为值类型(struct)引发的拷贝问题**:

  • 你在ViewModel的init中执行model.heartbeatEmitter.delegate = model时,因为struct是值类型,赋值时会自动产生一个独立的副本,所以delegate持有的并不是ViewModel内部存储的那个model实例,而是它的拷贝。
  • 后续定时器触发beat()方法时,修改的是这个副本的number属性,ViewModel中持有的原model实例没有发生任何变化,自然不会触发@Published的变更通知,UI也就不会更新。

另外补充:就算你把Model改为引用类型(class),@Published默认也只会在引用本身发生替换时才发送通知,修改引用对象的内部属性不会触发变更,也需要额外处理。


修复方案

这里提供两种常用的适配方案,你可以根据业务需求选择:

方案1:将委托接收方改为ViewModel(推荐,改动最小)

由ViewModel实现Heartbeat协议,直接修改自身持有的model实例,@Published会自动触发变更通知:

import Combine // 按需引入

class ViewModel: ObservableObject, Heartbeat {
    @Published private var model: Model
    private let emitter: HeartbeatEmitter
    
    init() {
        let emitter = HeartbeatEmitter()
        self.emitter = emitter
        model = Model(emitter: emitter)
        emitter.delegate = self // 委托指向ViewModel自身
    }
    
    var number: String {
        "\(model.number)"
    }
    
    // 实现Heartbeat协议
    func beat() {
        model.number += 1
        print(model.number)
    }
}

// 原Model中的beat方法可直接删除
struct Model {
    var heartbeatEmitter: HeartbeatEmitter
    var number: Int = 0
    
    init(emitter: HeartbeatEmitter){
        self.heartbeatEmitter = emitter
    }
}

方案2:将Model改为引用类型

如果你需要保留Model处理心跳逻辑的设计,可以把Model改为class,同时监听内部属性变更:

import Combine

class Model: Heartbeat, ObservableObject {
    let heartbeatEmitter: HeartbeatEmitter
    @Published var number: Int = 0
    
    init(emitter: HeartbeatEmitter){
        self.heartbeatEmitter = emitter
    }
    
    func beat() {
        number += 1
        print(number)
    }
}

class ViewModel: ObservableObject{
    @Published var number: String = ""
    private var model: Model
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        model = Model(emitter: HeartbeatEmitter())
        model.heartbeatEmitter.delegate = model
        // 监听Model的number属性变更,同步更新UI用属性
        model.$number
            .map { "\($0)" }
            .assign(to: &$number)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 06:45:00