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

SwiftUI init内赋值的@Published状态未刷新视图如何解决?

@Published属性未触发视图刷新的原理说明与修复

核心原理

  • @Published的刷新触发逻辑:@Published本质是对属性的willSet方法做了包装,只有当属性的内存地址发生变化(值类型赋值)或赋值的新对象与原有对象不是同一个引用(引用类型赋值)时,才会触发willSet回调,向ObservableObject的objectWillChange发布者推送事件,SwiftUI只有收到该事件才会刷新关联视图。
  • 引用类型集合的坑:你代码中用到的List<Wallet>是Realm框架提供的集合类型,属于引用类型。当你从数据库查询到的wallets集合和当前userWallets指向同一个内存地址时,赋值操作不会触发willSet,自然不会推送刷新事件。你重启模拟器后生效是因为首次初始化时属性是全新赋值,引用地址确实发生了变化,所以能触发刷新。
  • 回调线程问题:Amplify.DataStore.query的异步回调默认运行在后台队列,你外层包裹的DispatchQueue.main.async仅把查询的发起动作放到了主线程,回调的执行依然在后台队列。如果@Published的事件在非主线程发送,SwiftUI会忽略该事件,甚至抛出运行时警告。

修复方案

代码修改示例

final class DataStorePersistanceHandler: ObservableObject {
    
    @Published var userWallets: List<Wallet> = List<Wallet>()
    
    let authSessionManager = AuthSessionManager()
    
    init() {
        getWallets()
    }
    
    // MARK: Get local/online user wallets
    func getWallets() {
        let user = authSessionManager.getUser()
        Amplify.DataStore.query(User.self, byId: user.userId) { [weak self] result in
            // 所有回调逻辑统一调度到主线程执行
            DispatchQueue.main.async {
                guard let self = self else { return }
                switch result {
                case .success(let user): // 原代码此处变量名有误,查询的是User类型不是wallet
                    if let userWithWallets = user, let wallets = userWithWallets.wallets {
                        // 手动触发objectWillChange事件,即使引用不变也能推送刷新
                        self.objectWillChange.send()
                        // 如果需要值语义避免后续集合变更不触发刷新,可转成Array或者copy一份List
                        // self.userWallets = wallets.copy() as! List<Wallet>
                        self.userWallets = wallets
                    } else {
                        print("No wallets found for this user")
                    }
                case .failure(let error):
                    print("User not found - \(error.localizedDescription)")
                }
            }
        }
    }
}

额外优化建议

如果你的钱包数据会在数据库中实时更新,可以给userWallets添加Realm的集合变更通知,收到变更时手动调用objectWillChange.send()触发视图刷新,不需要每次都重新查询。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 05:54:03