ios 正在更新Coredata实体,但未刷新视图

ggazkfy8  于 2023-03-09  发布在  iOS
关注(0)|答案(1)|浏览(123)

我有两个实体,它们之间有一对多的关系,基本上一张票据上可以有许多产品,如下所示:Bill EntityProduct Entity
他们的班级:

extension Bill {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Bill> {
        return NSFetchRequest<Bill>(entityName: "Bill")
    }

    @NSManaged public var id: UUID?
    @NSManaged public var name: String?
    @NSManaged public var date: Date?
    @NSManaged public var products: NSSet?

    public var unwrappedID: UUID {
        id ?? UUID()
    }
    
    public var unwrappedName: String {
        name ?? "Unknown Bill Name"
    }
    
    public var unwrappedDate: Date {
        date ?? Date.now
    }
    
    public var formattedDate: String {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "pt_BR")
        formatter.timeZone = TimeZone(identifier: "GMT-3")
        formatter.dateFormat = "EEEE, MMM d, yyyy, HH:mm"
        return formatter.string(from: unwrappedDate)
    }
    
    public var productsArray: [Product] {
        let set = products as? Set<Product> ?? []
        
        return set.sorted {
            $0.unwrappedName < $1.unwrappedName
        }
    }
    
}

// MARK: Generated accessors for has
extension Bill {

    @objc(addHasObject:)
    @NSManaged public func addToProducts(_ value: Product)

    @objc(removeHasObject:)
    @NSManaged public func removeFromProducts(_ value: Product)

    @objc(addHas:)
    @NSManaged public func addToProducts(_ values: NSSet)

    @objc(removeHas:)
    @NSManaged public func removeFromProducts(_ values: NSSet)

}

extension Bill : Identifiable {

}

以及

extension Product {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Product> {
        return NSFetchRequest<Product>(entityName: "Product")
    }

    @NSManaged public var id: UUID?
    @NSManaged public var name: String?
    @NSManaged public var quantity: Int32
    @NSManaged public var price: Double
    @NSManaged public var bill: Bill?
    
    public var unwrappedId: UUID {
        id ?? UUID()
    }
    
    public var unwrappedName: String {
        name ?? "Unknown product name"
    }

}

extension Product : Identifiable {

}

当我想创建或删除一个对象时,视图(列表)通常会刷新,下面是我用来完成此操作的函数

private func addBill () {
        withAnimation {
        
            let bill = Bill(context: managedObjectContext)
            bill.id = UUID()
            bill.name = billName
            bill.date = Date.now
        
            try? managedObjectContext.save()
            
            billName = ""
            hideKeyboard()
            isShowing = false
        }
    }

    func deleteBill (offsets: IndexSet) {
        for offset in offsets {
            let bill = bills[offset]
            managedObjectContext.delete(bill)
        }
        
        try? managedObjectContext.save()
    }

    private func addProduct () {
        withAnimation {
            let product = Product(context: managedObjectContext)
            product.id = UUID()
            product.name = productName
            product.price = Double(productPrice) ?? 0.0
            product.quantity = 1
            product.bill = selectedBill
            product.bill?.id = selectedBill.id
            product.bill?.date = selectedBill.date
            product.bill?.name = selectedBill.unwrappedName
            
            try? managedObjectContext.save()
            
            productName = ""
            hideKeyboard()
            isShowing = false
        }
    }

    private func deleteProduct (offsets: IndexSet) {
        for offset in offsets {
            let product = selectedBill.productsArray[offset]
            managedObjectContext.delete(product)
        }
        
        try? managedObjectContext.save()
    }

我的问题发生在我试图更新产品的数量时。我有一个特定的视图称为计数器,它有一个加号按钮和一个减号按钮,当我点击它们时,核心数据会发生变化,但视图不会刷新,只有当我返回祖先视图并再次打开os产品列表时,我才能看到视图中的变化。
这是我的计数器类

struct CounterView: View {
    // MARK: - PROPERTIES
    @Environment(\.managedObjectContext) var managedObjectContext
    
    @State var selectedProduct: Product
    
    var body: some View {
        HStack {
            Button(action: {
                selectedProduct.quantity += 1
                try? self.managedObjectContext.save()
            }, label: {
                Image(systemName: "plus")
                    .foregroundColor(comandinhaGold)
                    .frame(width: 25, height: 25)
            })
            .buttonStyle(BorderlessButtonStyle())
            
            Text("\(selectedProduct.quantity)")
            
            Button(action: {
                if selectedProduct.quantity > 1 {
                    selectedProduct.quantity -= 1
                }
                try? self.managedObjectContext.save()
            }, label: {
                Image(systemName: "minus")
                    .foregroundColor(comandinhaGold)
                    .frame(width: 25, height: 25)
            })
            .buttonStyle(BorderlessButtonStyle())
        }
    }
}

我使用fetchrequest获取帐单列表,选择帐单后,我将按此方式列出产品

List {
     ForEach(selectedBill.productsArray, id: \.id) { product in
        HStack (spacing: 16){
           VStack(alignment: .leading, spacing: 5) {
              Text(product.unwrappedName)
                .foregroundColor(comandinhaGold)
                .font(.headline)
              Text("Preço un.: \(String(format: "R$ %.2f", product.price))")
                .font(.footnote)
           }
                                
           Spacer()
                                
           CounterView(selectedProduct: product)
        }
     }
     .onDelete(perform: deleteProduct)
  }

我尝试过使用以下命令强制视图刷新

@State var refresher = false

func updateView {
    refresher.toggle()
}

和其他类似的解决方案,似乎都不起作用。
尝试@Binding、@StateObject,但没有任何东西真正使带有数量的文本在单击按钮时更新为新值。

oalqel3c

oalqel3c1#

SwiftUI在区分引用类型和值类型方面非常严格。
@State@Binding仅适用于值类型。
另一方面,NSManagedObject是一个引用类型,但幸运的是它符合ObservableObject,引用类型的等价物是@StateObject@ObservedObject
所以简单的替换

@State var selectedProduct: Product

@ObservedObject var selectedProduct: Product

@State是错误的,在 *value类型的世界 * 中,它应该是@Binding

相关问题