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.