修改ViewModel值后@Published未更新UI问题咨询
解决UIHostingController中SwiftUI视图不跟随@Published属性更新的问题
问题原因
- 协议未支持Combine发布机制:原
DashboardSceneViewModel协议里的homeJson只是普通属性,没有暴露@Published的发布特性,导致SwiftUI无法识别到属性变化。 - 视图未监听ViewModel变化:
DashboardSceneView里的viewModel是普通变量,没加@ObservedObject修饰,SwiftUI没法追踪属性更新来刷新视图。 - ViewController存在初始化和赋值问题:原代码里
viewModel是可选类型,且赋值时的viewModel.data = response是错误写法,应该更新homeJson,同时要确保View和Controller共享同一个ViewModel实例。
修复方案
1. 修改ViewModel协议,支持ObservableObject
让协议继承ObservableObject,并把homeJson标记为@Published,确保遵循协议的类具备发布属性变化的能力:
import Combine protocol DashboardSceneViewModel: ObservableObject { var delegate: DashboardSceneViewDelegate? { get set } @Published var homeJson: Model? { get set } } class DefaultDashboardSceneViewModel: DashboardSceneViewModel { var delegate: DashboardSceneViewDelegate? @Published var homeJson: Model? }
2. 视图中用@ObservedObject监听ViewModel
在DashboardSceneView里用@ObservedObject修饰viewModel,这样SwiftUI会自动监听@Published属性的变化并刷新视图:
struct DashboardSceneView: View { @ObservedObject var viewModel: DashboardSceneViewModel var body: some View { VStack { if let homeJson = viewModel.homeJson { Text(homeJson.header ?? "") } Button("Tap"){ print("按钮点击") } } } }
3. 修正ViewController的初始化和赋值逻辑
初始化时直接传入ViewModel实例,确保View和Controller共享同一个对象,同时修正赋值方法:
final class DashboardSceneViewController: UIHostingController<DashboardSceneView> { private let viewModel: DashboardSceneViewModel init(viewModel: DashboardSceneViewModel) { self.viewModel = viewModel super.init(rootView: DashboardSceneView(viewModel: viewModel)) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func updateViewModel(with response: Model) { viewModel.homeJson = response } }
关键说明
- 协议继承
ObservableObject后,遵循类会自动拥有objectWillChange发布者,配合@Published可以让SwiftUI感知属性变化。 @ObservedObject专门用于监听外部传入的引用类型ViewModel,属性更新时会自动触发视图刷新。- 初始化ViewController时直接传入ViewModel实例,避免可选类型的空值问题,保证View和Controller操作的是同一个ViewModel。
内容的提问来源于stack exchange,提问作者user968597
相关产品推荐
相关产品推荐

