@EnvironmentObject 属性 在 swiftUI 中无法正常工作

@EnvironmentObject property not working properly in swiftUI

从 ViewModel 更新 cartArray 不会追加到当前元素,而是每次都会重新添加对象。我需要将 cartArray 维护为全局数组,以便可以从项目的任何视图访问它。我正在从 ViewModel 向 cartArray 添加元素。我使用了一个单独的 class DataStorage,它具有可以通过整个项目访问的对象

Example_AppApp.swift
import SwiftUI

@main
struct Example_AppApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(DataStorage())
        }
    }
}
DataStorage.swift

import Foundation

class DataStorage: ObservableObject {
    @Published var cartArray = [Book]()
}
ContentView.swift
import SwiftUI

struct ContentView: View {
    @State var showSheetView = false

    var body: some View {
        NavigationView{
            
        ListViewDisplay()
           .navigationBarItems(trailing:
                    Button(action: {
                        self.showSheetView.toggle()
                    }) {
                        Image(systemName: "cart.circle.fill")
                            .font(Font.system(.title))
                    }
                )
            
            
 
        }.sheet(isPresented: $showSheetView) {
            View3()
        }
        
    }
}



struct ListViewDisplay: View{
    
    
    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)

            NavigationLink(destination: View1(book: book)) {
            
        }
        }
        
}
}



View1Modal.swift

import Foundation

struct Book: Codable, Identifiable {
    var id:String{bookName}  
    var bookId : Int
    var bookName: String

}
 struct BookOption: Codable{
    var name: String
    var price: Int
}

View1ViewModel.swift
import Foundation
import Combine


class View1ViewModel : ObservableObject{
    
    var dataStorage = DataStorage()
   
    func addBook (bookId:Int ,bookName : String){
           dataStorage.cartArray.append(Book(bookId:bookId, bookName: bookName)) // Adding to global array
        print(dataStorage.cartArray)
    }
  
}

View1.swift
import SwiftUI

struct View1: View {
    
    @ObservedObject var vwModel = View1ViewModel()
    @EnvironmentObject var datastrg: DataStorage
   
    var book:Book
    
    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))
            
        })
        
 
        
    }
}

View3.swift

import SwiftUI

struct View3: View {
    @EnvironmentObject var datastorage : DataStorage
    var body: some View {
        NavigationView {
            List(datastorage.cartArray,id:\.id){book in

   
                    VStack{
                    Text(book.bookName)
                        .font(.custom("OpenSans-Bold", size: 20))
                          
                        }
                    
            }
            
                    .navigationBarTitle(Text("Cart"), displayMode: .inline)
                }
    }
}

当第一次调用 addBook 函数时,它打印为

[Example_App.Book(bookId: 1, bookName: "Catch-22")]

当我返回此 View1 并通过调用 addBook 添加另一本书时 func 它作为新对象添加到 cartArray

[Example_App.Book(bookId: 3, bookName: "Stephen King")]

打印 cartArray 中的元素数量给出 1 element 而不是 2 elements。当我转到 View3 并在列表中显示图书时,cartArray 显示为 empty(0 elements)

我认为 ViewModel class 中的 var dataStorage = DataStorage() 有问题。每次这是新创建的,所以不会存储 prevoius 值。但我不明白如何保持它的状态 如何在 View3 中显示列表?任何想法/建议都会有所帮助

您没有在任何地方调用您的函数 addBook,在调用该函数的 view3 中添加一个 onappear,您的列表将填充数据。

您需要 DataStorage 的一个实例 被传递。任何时候你写 DataStorage() 都会创建一个 新实例 .

.environmentObject 将允许您将该实例注入视图层次结构。然后,您可以使用 @EnvironmentObject 属性 包装器在 View.

中访问它

View1 中,我使用 onAppeardataStorage 属性 设置为 View1ViewModel -- 这意味着它必须是可选的View1ViewModel 因为它不会在 init 中设置。我避免在 init 中设置它的原因是因为 @EnvironmentObject 没有设置为 Viewinit -- 它在渲染时被注入。

@main
struct Example_AppApp: App {
    var dataStorage = DataStorage()
    
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(dataStorage)
        }
    }
}

class DataStorage: ObservableObject {
    @Published var cartArray = [Book]()
}

struct ContentView: View {
    @State var showSheetView = false
    
    var body: some View {
        NavigationView{
            
            ListViewDisplay()
                .navigationBarItems(trailing:
                                        Button(action: {
                    self.showSheetView.toggle()
                }) {
                    Image(systemName: "cart.circle.fill")
                        .font(Font.system(.title))
                }
                )
        }.sheet(isPresented: $showSheetView) {
            View3()
        }
    }
}

struct ListViewDisplay: View {
    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)
            NavigationLink(destination: View1(book: book)) {
                
            }
        }
        
    }
}

struct Book: Codable, Identifiable {
    var id:String{bookName}
    var bookId : Int
    var bookName: String
    
}

struct BookOption: Codable{
    var name: String
    var price: Int
}

class View1ViewModel : ObservableObject{
    
    var dataStorage : DataStorage?
    
    func addBook (bookId:Int ,bookName : String) {
        guard let dataStorage = dataStorage else {
            fatalError("DataStorage not set")
        }
        dataStorage.cartArray.append(Book(bookId:bookId, bookName: bookName)) // Adding to global array
        print(dataStorage.cartArray)
    }    
}

struct View1: View {
    
    @ObservedObject var vwModel = View1ViewModel()
    @EnvironmentObject var datastrg: DataStorage
    
    var book:Book
    
    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))
            
        })
            .onAppear {
                vwModel.dataStorage = datastrg
            }
    }
}

struct View3: View {
    @EnvironmentObject var datastorage : DataStorage
    var body: some View {
        NavigationView {
            List(datastorage.cartArray,id:\.id){book in
                VStack{
                    Text(book.bookName)
                        .font(.custom("OpenSans-Bold", size: 20))
                    
                }
            }
            .navigationBarTitle(Text("Cart"), displayMode: .inline)
        }
    }
}