Swift:如何更新可变形对象

时间:2019-04-18 05:48:37

标签: ios swift core-data

我正在尝试使用核心数据构建购物车,我创建了3个对象来对数据Product,Quantity和CartItem进行建模,其中包含产品和数量,并将它们另存为可转换对象到核心数据中。

我为xcdatamodeld创建了一个具有CartItem属性的类

@objc(CartItemContainer)
class CartItemContainer: NSManagedObject {
    @NSManaged var cartItemAttribute: CartItem
}

我可以毫无问题地保存到核心数据,但是每当我尝试使用下面的代码更新数量时,它都不会改变,仍然是1。

    static func changeQuantity(product: Product) {

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<CartItemContainer>(entityName: "CartItemContainer")

    var results: [CartItemContainer] = []
    do {
        results = try context.fetch(fetchRequest)
        if let productToChangeQuantityOn = results.first(where: {$0.cartItemAttribute.product.productID == product.productID}) {
            let oldQuantity = productToChangeQuantityOn.cartItemAttribute.quantity.value
            productToChangeQuantityOn.cartItemAttribute.quantity.value = oldQuantity + 1
            try context.save()
            context.refresh(productToChangeQuantityOn, mergeChanges: false)
        }
    }
    catch {
        print("error executing fetch request: \(error)")
    }
}

我尝试更新它而不调用context.refresh(productToChangeQuantityOn, mergeChanges: false) 它将在运行时更改数量,但是重新启动应用程序时,数量仍为1。

我在这里想念什么?

任何帮助将不胜感激。

更新: 例如,这是我设置产品的方式。数量和CartItem具有相同的设置。

class Product: NSObject, NSCoding, Decodable {

let productID: String
let category: String
let images: Dictionary<String, String>
let name: Dictionary<String, String>
let price: Dictionary<String, String>

func encode(with aCoder: NSCoder) {
    aCoder.encode(productID, forKey: "productID")
    aCoder.encode(category, forKey: "category")
    aCoder.encode(images, forKey: "images")
    aCoder.encode(name, forKey: "name")
    aCoder.encode(price, forKey: "price")
}

required init?(coder aDecoder: NSCoder) {
    self.productID = aDecoder.decodeObject(forKey: "productID") as! String
    self.category = aDecoder.decodeObject(forKey:"category") as! String
    self.images = aDecoder.decodeObject(forKey: "images") as! Dictionary<String, String>
    self.name = aDecoder.decodeObject(forKey: "name") as! Dictionary<String, String>
    self.price = aDecoder.decodeObject(forKey: "price") as! Dictionary<String, String>
}
}

2 个答案:

答案 0 :(得分:2)

欢迎使用核心数据,艾哈迈德。很高兴您能正常使用。在您开始之前,我想提出一个更常规的数据模型,从长远来看,它可能对您更好。不需要任何变形。enter image description here

广泛地,原因在Apple的Core Data Programming Guide状态的首页中给出了11个核心数据功能,列为要点。通过使用可变形的属性而不是关系,我想说的是您只是完全意识到了第一个和第五个要点的优点。

关于您的特定设计,我认为同一产品可以放在许多购物车中。通过为CartItem提供可转换类型的 product属性,必须以某种方式在每个购物车中复制相同的产品。如果要更改产品的属性,则在设计中,必须找到其中包含该产品的所有购物车并进行更改。使用常规设计,您只需更改Product对象。您的设计需要更多代码(通常是不好的),并且用户设备将使用更多资源,并且执行代码的速度变慢。

最后但并非最不重要的一点是,您不希望其他工程师在查看您的代码或数据模型时scratch之以鼻:)并且您希望能够从Apple文档,教程,博客文章,stackoverflow答案和您在互联网上找到的示例代码。如果您以非常规方式处理这些资源,那么这些资源将不适用。

答案 1 :(得分:0)

可变形属性是不可变类型,因此不能更改。更改它们的唯一方法是创建一个新对象,然后将其再次保存到核心数据中。

为解决这个问题,我从xcdatamodel中删除了属性cartItemAttribute,该属性同时包含产品和数量作为一个可转换属性。我将其替换为transformable类型的product属性和Int类型的quantity属性,现在一切正常。

这是我更新的代码

    static func changeQuantity(product: Product) {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<CartItemContainer>(entityName: "CartItemContainer")

    do {
        let results = try context.fetch(fetchRequest)
        if let productToChangeQuantityOn = results.first(where: {$0.product.productID == product.productID}) {
            let oldQuantity = productToChangeQuantityOn.quantity
            productToChangeQuantityOn.quantity = oldQuantity + 1
            try context.save()
            context.refresh(productToChangeQuantityOn, mergeChanges: false)
        }
    }
    catch {
        print("error executing fetch request: \(error)")
    }
}