SwiftUI iOS 14 视图不使用 @EnvironmentObject 更新 @Published 数组

Posted

技术标签:

【中文标题】SwiftUI iOS 14 视图不使用 @EnvironmentObject 更新 @Published 数组【英文标题】:SwiftUI iOS 14 View does not Update @Published Array with @EnvironmentObject 【发布时间】:2020-08-30 19:13:40 【问题描述】:

我正在开发一个卡路里跟踪器应用程序。 在我的应用程序中,我可以打开一些产品的详细信息,设置数量并将产品添加到“购物车”。 稍后,我想从数组中读出所有收集到的数据,并给他们一个简短的概述。

但是在对数组进行更改后,此视图将不会更新。 由于我使用 userDefaults 存储数据,我总是必须重新打开应用程序来更新视图。只有这样,孔阵列才会显示出来。

我的课堂购物车:

import Foundation

struct Order: Equatable, Identifiable, Codable 
    var id = UUID()
    var product: Product
    var modifier: Double
    var date: Date



class Cart: ObservableObject 
    
    @Published var orders = [Order]()
    
    static let saveKey = "SavedData"
    
    init() 
        
        if let data = UserDefaults.standard.data(forKey: Self.saveKey) 
            if let decoded = try? JSONDecoder().decode([Order].self, from: data) 
                self.orders = decoded
            
         else 
            self.orders = []
        
    
    
    // save order
    func save() 
        if let encoded = try? JSONEncoder().encode(self.orders) 
            UserDefaults.standard.set(encoded, forKey: Self.saveKey)
        
    
    
    // add to order
    func add(order: Order) 
        self.orders.append(order)
        print("product added to cart")
        save()
    
    
    // remove from order
    func remove(order: Order) 
        if let index = orders.firstIndex(of: order) 
            orders.remove(at: index)
        
    
    

我做了一个视图来应用任何特殊产品的数量。

import SwiftUI

struct AmountView: View 
    
    @EnvironmentObject var cart: Cart
    
    @State private var textInput = ""
    @State private var orderFinished = false
    var product: Product
        
    func StringDoubleConverter(text: String) -> String 
            return String(format: "%.2f", Double(textInput.replacingOccurrences(of: ",", with: ".")) ?? 0)
        
    
    var body: some View 
        VStack 
            Form 
                Section(header: Text("Mengenangabe")) 
                    
                    // input for the amount
                    AmountInputView(textInput: $textInput)
                    if !orderFinished 
                        Button("Hinzufügen", action: 
                            orderFinished = true
                            
                            hideKeyboard()
        
                            // add product to the cart
                            self.cart.add(order: Order(product: product, modifier: Double(StringDoubleConverter(text: textInput))!, date: Date()))

                            
                        )
                        .disabled(textInput == "")
                        .animation(.default)
                     else 
                        Text("Wurde zum Logbuch hinzugefügt")
                            .foregroundColor(.blue)
                    
                
                productNutritionCollectionView(product: product, modifier: Double(StringDoubleConverter(text: textInput))!)

            
        
    


struct AmountView_Previews: PreviewProvider 
    
    static var previews: some View 
        AmountView(product: Product.exampleProduct).environmentObject(Cart())
    

然后,我想使用 Form 和 ForEach lope 在日志视图中按顺序显示所有产品。

struct LogbookView: View 
    
    func deleteProducts(at offsets: IndexSet) 
        cart.orders.remove(atOffsets: offsets)
        cart.save()
    
    
    @EnvironmentObject var cart: Cart
    
    @State private var date = Date()
    
    var body: some View 
        NavigationView 
            Form 
                Section(header: Text("List")) 
                    ForEach(cart.orders)  order in
                        Text(order.product.name)
                    
                    .onDelete(perform:  indexSet in
                        deleteProducts(at: indexSet)
                    )
                    
                
            
            .navigationBarTitle(Text("Logbuch"), displayMode: .automatic)
            .navigationBarItems(trailing: DateView(date: $date))
        
    


struct LogbookView_Previews: PreviewProvider 
    
    
    static var previews: some View 
        LogbookView().environmentObject(Cart())
    

我正在使用 AppTab 视图来导航应用程序。因此,我将主 Struct 中的 AppTab View 更改为默认 View,环境对象为 Cart。

@main
struct KalorientrackerApp: App 
    
    var body: some Scene 
        
        WindowGroup 
            AppTabView().environmentObject(Cart())
        
    


struct KalorientrackerApp_Previews: PreviewProvider 
    static var previews: some View 
        Text("Hello, World!")
    

我正在使用 .sheet 打开我的 AmountView

struct ProductDetailView: View 
    
    @State private var showAmountView = false
    let product: Product
    
    var body: some View 
        VStack 
            // placeholder Image
            Image(product.fullImage)
                .clipShape(Circle())
                .padding(.top, 5)
            Spacer()
            
            Form 
                productNutritionCollectionView(product: product, modifier: 100)
            
        
        
        // Titel for Navigation bar
        .navigationBarTitle(Text(product.name), displayMode: .inline)
        
        // Button to go to amount view
        .navigationBarItems(trailing: Button(action: 
            self.showAmountView = true
        , label: 
            Image(systemName: "plus.circle")
                .padding(.leading, 20)
        ).sheet(isPresented: $showAmountView, content: 
            
            AmountView(product: product).environmentObject(Cart())
        ))
    


struct ProductDetailView_Previews: PreviewProvider 
    static var previews: some View 
        ProductDetailView(product: Product.exampleProduct)    

我已经找到了一些其他的讨论,但它们对我没有用。

我正在使用 Xcode 12 beta 6 和 ios14 beta 6

【问题讨论】:

您是否在 SceneDelegate 中添加了您的环境变量? window.rootViewController = UIHostingController(rootView: contentView.environmentObject(Cart())) 然后初始化你的 Cart 类加载 UserDefaults SceneDelegate 在 Xcode12 中不再可用。这是一个在 Xcode 测试版中制作的新项目。我将购物车添加到 @main 结构中。 据我所知,您没有提供代码的问题部分。你会展示你创建购物车的部分,你如何列出订单,你如何创建工作表......还是我们应该猜测? 对不起。将缺失的代码添加到问题中。 我遇到了类似的问题。这篇文章为我解决了这个问题:***.com/questions/57615920/… 【参考方案1】:

我自己发现了这个错误。问题是,我在.sheet 操作中明确提交了一个 .environmentObject。

AmountView(product: product).environmentObject(Cart())

我从.sheet 操作中删除了.environmentObject(Cart())。现在它正在工作。

认为这会导致错误,因为我在项目的主视图中使用了 .environmentObject(Cart()) 运算符。

【讨论】:

以上是关于SwiftUI iOS 14 视图不使用 @EnvironmentObject 更新 @Published 数组的主要内容,如果未能解决你的问题,请参考以下文章

iOS 14 SwiftUI 键盘自动提升视图

SwiftUI禁止用户关闭sheet弹出视图在iOS14.6+失效的巧妙解决

SwiftUI禁止用户关闭sheet弹出视图在iOS14.6+失效的巧妙解决

SwiftUI禁用列表边框iOS 14 [重复]

SwiftUI禁用列表边框iOS 14 [重复]

在 SwiftUI iOS 14 中旋转视图