删除领域中的购物车项目时出现问题

问题描述 投票:0回答:1

在此视图中,如果我尝试发送另一个视图(如 CartItem()),则应用程序会崩溃并出现错误线程 1:“对象已被删除或失效。”如果我再次进入应用程序,caritem 就会被删除! 我认为对象是在使用的地方

import Foundation
import RealmSwift

class ApiResponse: Decodable {
    let status: Bool
    let page: String
    let category: String
    let results: [Product]
}

class Product: Object, Identifiable, Decodable {
    @Persisted var product_id: String
    @Persisted var product_name: String
    @Persisted var product_price: String
    @Persisted var product_group: String
    @Persisted var product_description: String
    @Persisted var product_thumb_images: String
    @Persisted var product_big_images: String
    @Persisted var isInCart: Bool = false
//    @Persisted var quantity: Int = 1 // Default quantity is 1

    enum CodingKeys: String, CodingKey {
        case product_id, product_name, product_price, product_group, product_description, product_thumb_images, product_big_images
    }
    
    override class func primaryKey() -> String? {
        return "product_id"
    }
}

class CartItem: Object,Identifiable {
    @Persisted var product: Product?
    @Persisted var quantity: Int = 1

    convenience init(product: Product, quantity: Int) {
        self.init()
        self.product = product
        self.quantity = quantity
    }
}

import Foundation
import Alamofire
import SwiftUI
import RealmSwift
import Realm

class ProductViewModel: ObservableObject {
    @Published var products: [Product]?
    @Published var errorMessage: String?
    @Published var cartItems: [CartItem] = []
    @Published var selectedCategory: String = "All"

    internal func fetch() {
        let urlString: String
        if selectedCategory == "All" {
            urlString = ""
        } else {
            urlString = ""
        }
        guard let url = URL(string: urlString) else {
            self.errorMessage = "Invalid URL"
            return
        }

        AF.request(url)
            .validate()
            .responseDecodable(of: ApiResponse.self) { response in
                switch response.result {
                case .success(let apiResponse):
                    self.products = apiResponse.results
                case .failure(let error):
                    self.errorMessage = "Error fetching data: \(error)"
                }
            }
    }

    func addToCart(product: Product) {
        do {
            let realm = try Realm()

            if let existingProduct = realm.object(ofType: Product.self, forPrimaryKey: product.product_id) {
                try realm.write {
                    if existingProduct.isInCart {
                        if let existingCartItem = cartItems.first(where: { $0.product?.product_id == product.product_id }) {
                            existingCartItem.quantity += 1
                        } else {
                            // Create a new CartItem with quantity 1
                            let cartItem = CartItem(product: existingProduct, quantity: 1)
                            realm.add(cartItem)
                        }
                    } else {
                        // Update the isInCart property and add to cart
                        existingProduct.isInCart = true
                        // Create a new CartItem with quantity 1
                        let cartItem = CartItem(product: existingProduct, quantity: 1)
                        realm.add(cartItem)
                    }
                }
            } else {
                // Product does not exist in the database, handle accordingly
                // Create a new CartItem with quantity 1
                let cartItem = CartItem(product: product, quantity: 1)
                try realm.write {
                    realm.add(cartItem)
                }
            }

            updateCartItems()
        } catch {
            print("Error adding to cart: \(error)")
        }
    }



    func removeFromCart(product: Product) {
        do {
            let realm = try Realm()
            if let existingCartItem = cartItems.first(where: { $0.product?.product_id == product.product_id }) {
                if existingCartItem.quantity > 1 {
                    try realm.write {
                        existingCartItem.quantity -= 1
                    }
                } else {
                    // Update the isInCart property and remove from cart
                    if let existingProduct = existingCartItem.product {
                        try realm.write {
                            existingProduct.isInCart = false
                        }
                    }
                    try realm.write {
                        realm.delete(existingCartItem)
                    }
                }
                updateCartItems()
            }
        } catch {
            print("Error removing from cart: \(error)")
        }
    }


    internal func updateCartItems() {
        do {
            let realm = try Realm()
            cartItems = Array(realm.objects(CartItem.self))
        } catch {
            print("Error updating cart items: \(error)")
        }
    }

    func calculateTotalPrice() -> Double {
        return cartItems.reduce(0) { $0 + Double($1.quantity) * Double($1.product?.product_price ?? "0")! }
    }
}

//
//  AddCartView.swift
//  ZED_Shop
//
//  Created by JARVIS on 22/12/23.
//

import SwiftUI

struct AddCartView: View {
    @ObservedObject var viewModel: ProductViewModel

    var body: some View {
        NavigationView {
            VStack {
                if viewModel.cartItems.isEmpty {
                    Text("Your cart is empty.")
                } else {
                    List {
                        ForEach(viewModel.cartItems) { cartItem in
                            VStack() {
                                HStack {
                                    VStack{
                                        Text(cartItem.product?.product_name ?? "Unknown Product")
                                            .font(.smallCaps(.title3)())
                                            .frame(maxWidth: .infinity, alignment: .leading)
                                            .padding(.top)
                                            .padding(.leading)
                                        Text("\(cartItem.product?.product_price ?? "0")")
                                            .font(.title)
                                            .fontWeight(.bold)
                                            .frame(maxWidth: .infinity, alignment: .leading)
                                            .padding(.leading)
                                            .foregroundColor(.blue)
                                        Text("\(cartItem.quantity)")
                                            .foregroundColor(.black)
                                            .padding(.bottom)
                                    }
                                    Spacer()
                                    HStack{
                                        RemoteImage(url: URL(string: cartItem.product!.product_thumb_images))
                                            .frame(width: 130, height: 170)
                                    }
                                }
                            }
                        }
                        .onDelete(perform: { indexSet in
                            viewModel.removeFromCart(product: viewModel.cartItems[indexSet.first!].product!)
                        })
                    }
                }

                Text("Total Price: \(viewModel.calculateTotalPrice())")

                Button("Checkout") {
                    // Handle checkout logic
                }
                .disabled(viewModel.cartItems.isEmpty)
            }
            .navigationTitle("Cart")
            .onAppear {
                viewModel.updateCartItems() // Fetch cart items on appear
            }
        }
    }
}

struct AddCartView_Previews: PreviewProvider {
    static var previews: some View {
        return AddCartView(viewModel: ProductViewModel())
    }
}

import SwiftUI
import RealmSwift

struct CartItemView: View {
    @ObservedObject var viewModel: ProductViewModel
    let cartItem: CartItem
    let product: Product
    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                HStack {
                    Text(cartItem.product?.product_name ?? "Unknown Product")
                        .font(.smallCaps(.title3)())
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .padding(.top)
                        .padding(.leading)
                    Spacer()
                    Button(action: {
                        // Handle delete action
                        withAnimation {
                            viewModel.removeFromCart(product: cartItem.product!)
                        }                 }) {
                            Image(systemName: "trash")
                                .foregroundColor(.red)
                        }
                        .padding(.top)
                        .padding(.trailing)
                        .frame(width: 25, height: 25)
                    Spacer()
                }
                
                Text("₹\(String(format: "%.2f", viewModel.calculateTotalPrice()))")
                    .font(.title)
                    .fontWeight(.bold)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .padding(.leading)
                    .foregroundColor(.blue)
                
                HStack {
                    Button(action: {
                        // Decrease quantity action

                    }) {
                        Text("-")
                            .frame(width: 50, height: 50)
                            .background(.blue.opacity(0.1))
                            .cornerRadius(10)
                            .foregroundColor(.black)
                    }
                    
                    .padding(.bottom)
                    .padding(.leading, 20)
                    Spacer()
                    
                    Text("\(cartItem.quantity)")
                        .foregroundColor(.black)
                        .padding(.bottom)
                    
                    Spacer()
                    Button(action: {
                        // Increase quantity action
                    }) {
                        Text("+")
                            .frame(width: 50, height: 50)
                            .background(.blue.opacity(0.1))
                            .cornerRadius(10)
                            .foregroundColor(.black)
                    }
                    
                    .padding(.bottom)
                    Spacer()
                }
                .frame(maxWidth: 200)
                
                Spacer()
                
            }
            .frame(maxWidth: .infinity)
            .frame(height: 170)
            
            RemoteImage(url: URL(string: cartItem.product!.product_thumb_images))
                .frame(width: 130, height: 170)
                .frame(alignment: .trailing)
            
        }
        .frame(maxWidth: .infinity)
        .frame(height: 170)
        .background(Color.gray.opacity(0.1))
        .cornerRadius(10)
        .shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2)
        .padding(.leading)
        .padding(.trailing)
    }

}

请给我这个问题的解决方案

我想像 AddtoCartView 中的 CartItem

struct AddCartView: View {
    @ObservedObject var viewModel: ProductViewModel

    var body: some View {
        NavigationView {
            VStack {
                if viewModel.cartItems.isEmpty {
                    Text("Your cart is empty.")
                } else {
                    List {
                        ForEach(viewModel.cartItems) { cartItem in
                            VStack() {
                                CartItemView(
                                    viewModel:viewModel,
                                    cartItem: cartItem, product: cartItem.product!
                                )
                            }
                        }
                        .onDelete(perform: { indexSet in
                            viewModel.removeFromCart(product: viewModel.cartItems[indexSet.first!].product!)
                        })
                    }
                }

                Text("Total Price: \(viewModel.calculateTotalPrice())")

                Button("Checkout") {
                    // Handle checkout logic
                }
                .disabled(viewModel.cartItems.isEmpty)
            }
            .navigationTitle("Cart")
            .onAppear {
                viewModel.updateCartItems() // Fetch cart items on appear
            }
        }
    }
}

struct AddCartView_Previews: PreviewProvider {
    static var previews: some View {
        return AddCartView(viewModel: ProductViewModel())
    }
}
ios swift swiftui realm
1个回答
0
投票

因为这是 SwiftUI,所以你不应该有视图模型对象,这是视图结构层次结构的工作。状态应该分散在小的视图结构中,让只读或

@Binding
用于读/写,你不应该在每个视图中都有
@ObservedObject
,这会减慢它的速度,也许是它崩溃的原因。尝试将
ProductViewModel
重命名并拆分为
ProductFetcher
/
CartFetcher
,并且仅包含获取代码并从中删除所有视图数据,例如就像
selectedCategory

© www.soinside.com 2019 - 2024. All rights reserved.