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

SwiftUI扩展内无法获取@Published属性更新的问题求助

问题分析与解决方案

核心问题

  1. 实例不共享:你在RecordView中初始化myViewModel时,传入的是新创建的WatchManager实例(ViewModel(watchManager: WatchManager())),而非视图中已有的watchManager对象。这导致ViewModel和视图使用的是两个完全独立的WatchManager,自然无法同步更新。
  2. 未监听@Published变化:即使传入了正确的WatchManager实例,你的ViewModel只是把它作为普通属性存储,没有监听其@Published属性的变更,所以deltaDistance更新时,deltaDistance2不会自动同步。

修正方案

步骤1:共享WatchManager实例

将RecordView中myViewModel的初始化改为传入当前的watchManager,避免创建新实例:

struct RecordView: View {
    @StateObject private var watchManager: WatchManager
    @StateObject private var myViewModel: ViewModel
    
    // 在视图初始化时统一创建并共享实例
    init() {
        let manager = WatchManager()
        self._watchManager = StateObject(wrappedValue: manager)
        self._myViewModel = StateObject(wrappedValue: ViewModel(watchManager: manager))
    }
    
    // 剩余body代码不变
}

步骤2:在ViewModel中监听WatchManager的更新

有两种方式实现自动同步:

方式一:Async/Await 订阅(Swift 5.5+)

extension RecordView {
    @MainActor class ViewModel: ObservableObject {
        @ObservedObject var watchManager: WatchManager
        @Published var deltaDistance2 = 0.0
        
        init(watchManager: WatchManager) {
            self.watchManager = watchManager
            // 初始同步值
            self.deltaDistance2 = watchManager.deltaDistance
            
            // 订阅deltaDistance的变化,自动更新
            Task {
                for await _ in watchManager.$deltaDistance.values {
                    self.deltaDistance2 = watchManager.deltaDistance
                }
            }
        }
        
        // 保留手动同步方法(如果需要)
        func setWithOtherDistance() {
            deltaDistance2 = watchManager.deltaDistance
        }
    }
}

方式二:Combine 订阅

import Combine

extension RecordView {
    @MainActor class ViewModel: ObservableObject {
        private var watchManager: WatchManager
        @Published var deltaDistance2 = 0.0
        private var cancellables = Set<AnyCancellable>()
        
        init(watchManager: WatchManager) {
            self.watchManager = watchManager
            self.deltaDistance2 = watchManager.deltaDistance
            
            // 绑定deltaDistance的变化到deltaDistance2
            watchManager.$deltaDistance
                .assign(to: \.deltaDistance2, on: self)
                .store(in: &cancellables)
        }
        
        func setWithOtherDistance() {
            deltaDistance2 = watchManager.deltaDistance
        }
    }
}

完整修正代码

import SwiftUI
import Combine // 使用Combine方式时需要导入

struct RecordView: View {
    @StateObject private var watchManager: WatchManager
    @StateObject private var myViewModel: ViewModel
    
    init() {
        let manager = WatchManager()
        self._watchManager = StateObject(wrappedValue: manager)
        self._myViewModel = StateObject(wrappedValue: ViewModel(watchManager: manager))
    }
    
    var body: some View {
        HStack {
            Text("Distance: \(watchManager.deltaDistance)")
        }
        .padding()
        
        HStack {
            Text("Distance2: \(myViewModel.deltaDistance2)")
            Button("set DeltaDistance2") {
                myViewModel.setWithOtherDistance()
            }
            // 新增测试按钮:触发WatchManager更新
            Button("Update Watch Data") {
                watchManager.setDistance()
            }
        }
        .padding()
    }
}

extension RecordView {
    @MainActor class ViewModel: ObservableObject {
        @ObservedObject var watchManager: WatchManager
        @Published var deltaDistance2 = 0.0
        
        init(watchManager: WatchManager) {
            self.watchManager = watchManager
            self.deltaDistance2 = watchManager.deltaDistance
            
            // 用Async/Await订阅更新
            Task {
                for await _ in watchManager.$deltaDistance.values {
                    self.deltaDistance2 = watchManager.deltaDistance
                }
            }
        }
        
        func setWithOtherDistance() {
            deltaDistance2 = watchManager.deltaDistance
        }
    }
}

class WatchManager: ObservableObject {
    @Published var deltaDistance = 0.0
    
    func setDistance() {
        self.deltaDistance = 9.0
    }
}

关键说明

  • 必须保证WatchManager实例唯一,ViewModel和视图使用同一个对象,才能实现数据同步。
  • 通过订阅@Published的数据流,可实现deltaDistance更新时自动同步deltaDistance2,无需手动触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 10:26:05