SwiftUI中@EnvironmentObject功能异常:ViewModel更新全局cartArray无法追加元素及View3购物车列表无法显示问题求助
问题根源分析
你遇到的两个问题本质上是同一个原因:状态不共享。
- 在
View1ViewModel中,你直接创建了新的DataStorage实例(var dataStorage = DataStorage()),这意味着每次生成View1ViewModel时,都会得到一个独立的购物车数组——和App全局注入的那个DataStorage完全无关。所以每次调用addBook都是往新数组里加元素,自然看不到累积效果。 View3使用的是App全局注入的DataStorage(通过@EnvironmentObject),但ViewModel操作的是自己的私有实例,两者数据完全隔离,所以View3里的购物车始终为空。
解决方案:依赖注入共享全局实例
核心思路是让View1ViewModel使用App全局的DataStorage实例,而不是自己新建。我们通过依赖注入的方式把全局实例传给ViewModel,确保所有组件操作的是同一个数据源。
步骤1:修改View1ViewModel,接收外部传入的DataStorage
把ViewModel中自己创建的DataStorage改为通过初始化方法传入,确保使用全局实例:
import Foundation import Combine class View1ViewModel : ObservableObject{ private let dataStorage: DataStorage // 通过初始化注入全局DataStorage实例 init(dataStorage: DataStorage) { self.dataStorage = dataStorage } func addBook (bookId:Int ,bookName : String){ dataStorage.cartArray.append(Book(bookId:bookId, bookName: bookName)) print(dataStorage.cartArray) } }
步骤2:修改ListViewDisplay,传递全局DataStorage给View1
让ListViewDisplay获取全局的DataStorage,并在导航到View1时传递给它:
import SwiftUI struct ListViewDisplay: View{ @EnvironmentObject var datastrg: DataStorage // 获取全局实例 var book = [ Book(bookId: 1 ,bookName: "Catch-22"), Book(bookId: 2 ,bookName: "Just-Shocking" ), Book(bookId: 3 ,bookName: "Stephen King" ), Book(bookId: 4,bookName: "A Gentleman in Moscow"), ] var body: some View { List(book, id: \.id) { book in Text(book.bookName) // 把全局DataStorage传给View1 NavigationLink(destination: View1(book: book, dataStorage: datastrg)) { } } } }
步骤3:修改View1,用传入的DataStorage初始化ViewModel
更新View1的初始化方法,接收DataStorage并创建ViewModel:
import SwiftUI struct View1: View { @StateObject private var vwModel: View1ViewModel var book:Book init(book: Book, dataStorage: DataStorage) { self.book = book // 用全局DataStorage初始化ViewModel self.vwModel = View1ViewModel(dataStorage: dataStorage) } var body: some View { Text(book.bookName).font(.title) Spacer() Button(action: { vwModel.addBook(bookId: book.bookId, bookName: book.bookName) }, label: { Text("Add Book to Cart") .frame(maxWidth: .infinity, minHeight: 60) .background(Color.red) .foregroundColor(Color.white) .font(.custom("OpenSans-Bold", size: 24)) }) } }
验证效果
现在所有组件都使用同一个全局DataStorage实例:
- 点击
View1的"Add Book to Cart"按钮时,ViewModel会往全局购物车数组追加元素,打印结果会显示数组长度逐渐增加; - 打开
View3的购物车弹窗时,@EnvironmentObject会获取到最新的购物车数据,正确显示所有添加的书籍。
内容的提问来源于stack exchange,提问作者Honey
相关产品推荐
相关产品推荐

