繁体   English   中英

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

[英]@EnvironmentObject property not working properly in swiftUI

从 ViewModel 更新 carArray 不会附加到当前元素,而是每次都新鲜添加对象。 我需要将cartArray 维护为全局数组,以便可以从项目的任何视图访问它。 我正在从 ViewModel 向 carArray 添加元素。 我采用了一个单独的类 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 func 时,它打印为

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

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

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

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

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

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

您正在视图模型中创建一个本地 DataStorage,而不是使用 @EnvironmentObject 中的一个,因此将其注入到视图模型中。

首先更改视图模型,因此您必须注入 DataStorage

class ViewModel: ObservableObject {
    var dataStorage: DataStorage
    //...

    init(dataStorage: DataStorage) {
        self.dataStorage = dataStorage
    }
    //...
}

然后更改View1以便在init创建视图模型

struct View1: View {
    @ObservedObject var vwModel: ViewModel
    @EnvironmentObject var datastrg: DataStorage

    init() {
        vwModel = ViewModel(dataStorage: datastrg)
    }
    //...
}

您需要有一个可以传递的DataStorage 任何时候你编写DataStorage()来创建一个新实例

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

内部View1 ,我用onAppear设置dataStorage在性能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)
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM