简体   繁体   中英

SwiftUI iOS 14 View does not Update @Published Array with @EnvironmentObject

I'm working on a calorie-tracker app. In my App, I can open the Detail side of some products, set the amount and add the product to the "Cart". Later, I want to read out all collected datas from the array and show them an a short overview.

But this View won't be updated after making changer on the array. Due to I storage the datas with the userDefaults, I always have to reopen the app to update the view. Only then, the hole array will be displayed.

My Class Cart:

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)
        }
    }
    
}

I made a View to apply the amount of any special product.

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())
    }
}

Then, I want to display all products in the order in a logbook view using a Form and a 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())
    }
}

I'm using a AppTab View to navigate the app. Therefore, I changed the AppTab View in the main Struct to the default View with an environment object of 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!")
    }
}

I'm opening my AmountView using a .sheet

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)    }
}

I already found some other discussions, but they didn't worked for me.

I'm using Xcode 12 beta 6 and iOS14 beta 6

I found the bug myself. The problem was, that I committed explicit an .environmentObject in my .sheet action.

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

I removed .environmentObject(Cart()) from the .sheet action. Now it's working.

Thinking this caused the bug because I'm using the .environmentObject(Cart()) operator in the main View of my project.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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