SwiftUI视图不更新求助:已用@Published与@ObservedObject
问题分析与解决方案
嘿,我一眼就揪出问题的根源啦!你现在遇到的HomeView不更新的核心问题,是你在AddView和HomeView里分别创建了完全独立的AddViewModel实例——简单说就是,AddView里往自己的viewModel数组加狗,HomeView的viewModel根本没收到这个变化,当然不会更新UI咯!
问题拆解
你看:
- 在AddView里你写了
@ObservedObject var viewModel = AddViewModel() - 在HomeView里又写了
@ObservedObject var viewModel = AddViewModel()
这两行代码会生成两个毫无关联的AddViewModel对象,就像两个不同的文件夹,你往A文件夹里放文件,B文件夹当然不会自动出现这个文件啦!
解决方案:共享同一个ViewModel实例
我们需要让AddView和HomeView共用同一个AddViewModel对象,这里推荐两种常用方式:
方式一:使用EnvironmentObject(最适合全局共享场景)
在App入口注入ViewModel
找到你的App主文件(比如YourDogApp.swift),初始化ViewModel并把它注入到整个App的环境中:@main struct YourDogApp: App { // 只在这里初始化一次ViewModel private let addViewModel = AddViewModel() var body: some Scene { WindowGroup { HomeView() .environmentObject(addViewModel) // 注入到环境 } } }在View中获取共享的ViewModel
- 修改HomeView,去掉自己初始化的代码,改用
@EnvironmentObject获取:struct HomeView: View { @EnvironmentObject var viewModel: AddViewModel var body: some View { ScrollView { VStack { ForEach(viewModel.dogs) { dog in CardView(dog: dog) Text(dog.name) } } } } } - 修改AddView,同样改用
@EnvironmentObject获取:struct AddView: View { @EnvironmentObject var viewModel: AddViewModel // 去掉原来的@ObservedObject var viewModel = AddViewModel() // 你的其他属性(name、selectedRace等)和UI代码... .navigationBarItems(trailing: Button("Publish") { viewModel.dogs.append(Dog(name: self.name, race: races[selectedRace], age: self.age, gender: genders[selectedGender], sterile: self.isSterile, pictureURL: "", location: "", dogFriendly: self.isDogFriendly, catFriendly: self.isCatFriendly, childFriendly: self.isChildFriendly, needsGarden: self.needsGarden, isClean: self.isClean)) print(viewModel.dogs) }) }
- 修改HomeView,去掉自己初始化的代码,改用
方式二:父视图传递ViewModel(适合局部共享场景)
如果你的ViewModel只需要在HomeView和它导航的AddView之间共享,也可以直接传递:
- HomeView持有ViewModel
struct HomeView: View { @ObservedObject var viewModel = AddViewModel() var body: some View { NavigationStack { // 或者NavigationView,看你的SwiftUI版本 ScrollView { VStack { ForEach(viewModel.dogs) { dog in CardView(dog: dog) Text(dog.name) } } } .navigationDestination(for: AddView.self) { AddView(viewModel: viewModel) // 传递同一个ViewModel实例 } } } } - AddView接收传递的ViewModel
struct AddView: View { @ObservedObject var viewModel: AddViewModel // 不再自己初始化 // 你的其他属性和UI代码... .navigationBarItems(trailing: Button("Publish") { viewModel.dogs.append(/* 你的Dog实例 */) }) }
额外提醒
不管用哪种方式,核心都是保证所有需要响应数据变化的View,绑定的是同一个ViewModel实例。另外,你的Dog结构体已经是Identifiable的,ForEach可以正常遍历,这部分没问题~
内容的提问来源于stack exchange,提问作者Jihaysse
相关产品推荐
相关产品推荐

