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

SwiftUI中@EnvironmentObject功能异常:ViewModel更新全局cartArray无法追加元素及View3购物车列表无法显示问题求助

问题根源分析

你遇到的两个问题本质上是同一个原因:状态不共享。

  1. 在View1ViewModel中,你直接创建了新的DataStorage实例(var dataStorage = DataStorage()),这意味着每次生成View1ViewModel时,都会得到一个独立的购物车数组——和App全局注入的那个DataStorage完全无关。所以每次调用addBook都是往新数组里加元素,自然看不到累积效果。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 20:27:50