【问题标题】:Swift - How to debug a core data relationship error?Swift - 如何调试核心数据关系错误?
【发布时间】:2020-12-17 10:25:00
【问题描述】:

我正在创建一个产品的核心数据对象,该产品还与许多其他产品以多对多关系关联。

在转换我的 json 时,我会检查该产品是否具有关联产品,然后添加关系。

if let relatedItems = response["related"] as? [[String:Any]] {
    // create the related items
    for d in relatedItems {
        let related = try createAssociatedFromResponse(response: d)
        product.addToAssociatedProducts(related)
        try self.managedObjectContext.save()
    }
}

这会产生一个不稳定的错误 - 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“对象不应同时被修改和附加”

我已尝试检查对象是否已作为关系存在,但仍然出现此错误。

编辑 - 将 json 转换为核心数据对象的完整代码

func createFromResponse(response: Dictionary<String, Any>) throws -> Product {
        
        let productID = response["id"] as! NSNumber
        
        var product: Product!
        
        let fetchRequest: NSFetchRequest<Product> = Product.fetchRequest()
        fetchRequest.predicate = NSPredicate(format: "productID = %@", productID)
        
        if let fetchedProduct = try self.managedObjectContext.fetch(fetchRequest).first {
            product = fetchedProduct
        } else {
            product = (NSEntityDescription.insertNewObject(forEntityName: "Product", into: self.managedObjectContext) as! Product)
            product.productID = productID
        }
        
        product.name = response["name"] as? String
        product.ref = response["ref"] as? String
        product.desc = response["description"] as? String
        product.imageURL = response["image"] as? String
        product.image = nil
        product.thumbImageURL = response["thumb"] as? String
        product.thumbImage = nil
        product.pdfURL = response["pdf"] as? String
        product.manufacturerUrl = response["manufacturer_url"] as? String
        
        if let categoriesInHierarchy = response["categories"] as? NSArray
        {
            if categoriesInHierarchy.count == 3
            {
                if let topCategory = categoriesInHierarchy[0] as? [String:Any] {
                    product.topCategoryID = topCategory["id"] as? NSNumber
                    product.topCategoryName = topCategory["name"] as? String
                }
                
                if let subCategory = categoriesInHierarchy[1] as? [String:Any] {
                    product.subCategoryID = subCategory["id"] as? NSNumber
                    product.subCategoryName = subCategory["name"] as? String
                }
                
                if let bottomCategory = categoriesInHierarchy[2] as? [String:Any] {
                    product.bottomCategoryID = bottomCategory["id"] as? NSNumber
                    product.bottomCategoryName = bottomCategory["name"] as? String
                }
                
            }
        }
        
        if let relatedItems = response["related"] as? [[String:Any]] {
            // create the related items
            for d in relatedItems {
                let related = try createAssociatedFromResponse(response: d)
                product.addToAssociatedProducts(related)
            }
            try self.managedObjectContext.save()
        }
        
        return product
    }

func createAssociatedFromResponse(response: Dictionary<String, Any>) throws -> Product {
        
        let productID = response["id"] as! NSNumber
        
        var product: Product!
        
        let fetchRequest: NSFetchRequest<Product> = Product.fetchRequest()
        fetchRequest.predicate = NSPredicate(format: "productID = %@", productID)
        
        if let fetchedProduct = try self.managedObjectContext.fetch(fetchRequest).first {
            product = fetchedProduct
        } else {
            product = (NSEntityDescription.insertNewObject(forEntityName: "Product", into: self.managedObjectContext) as! Product)
            product.productID = productID
        }
        
        product.name = response["name"] as? String
        product.ref = response["ref"] as? String
        product.desc = response["description"] as? String
        product.imageURL = response["image"] as? String
        product.image = nil
        product.thumbImageURL = response["thumb"] as? String
        product.thumbImage = nil
        product.pdfURL = response["pdf"] as? String
        product.manufacturerUrl = response["manufacturer_url"] as? String
        
        if let categoriesInHierarchy = response["categories"] as? NSArray
        {
            if categoriesInHierarchy.count == 3
            {
                if let topCategory = categoriesInHierarchy[0] as? [String:Any] {
                    product.topCategoryID = topCategory["id"] as? NSNumber
                    product.topCategoryName = topCategory["name"] as? String
                }
                
                if let subCategory = categoriesInHierarchy[1] as? [String:Any] {
                    product.subCategoryID = subCategory["id"] as? NSNumber
                    product.subCategoryName = subCategory["name"] as? String
                }
                
                if let bottomCategory = categoriesInHierarchy[2] as? [String:Any] {
                    product.bottomCategoryID = bottomCategory["id"] as? NSNumber
                    product.bottomCategoryName = bottomCategory["name"] as? String
                }
                
            }
        }
        
        product.associatedProducts = nil
        
        return product
    }

【问题讨论】:

  • 确保添加 Core Data 调试标志以帮助调试。参见例如here

标签: ios swift iphone core-data


【解决方案1】:

你能在for循环之后移动try self.managedObjectContext.save()吗,像这样:

if let relatedItems = response["related"] as? [[String:Any]] {
    // create the related items
    for d in relatedItems {
        let related = try createAssociatedFromResponse(response: d)
        product.addToAssociatedProducts(related)
    }
    try self.managedObjectContext.save()
}

编辑:
你是如何在createAssociatedFromResponse 中创建对象的?

编辑 2:
您不应该在不同的线程中使用NSManagedObjectContext,将您的函数包装在perform 块中,如下所示:

self.managedObjectContext.perform { 
 if let relatedItems = response["related"] as? [[String:Any]] {
    // create the related items
    for d in relatedItems {
        let related = try createAssociatedFromResponse(response: d)
        product.addToAssociatedProducts(related)
    }
    try self.managedObjectContext.save()
 }
}

【讨论】:

  • 我已经尝试过了,但我仍然有同样的错误。我现在添加了完整的代码。
  • createFromResponse 函数在哪个线程上调用?我想它在后台线程上?
  • 是的,它在循环 JSON 响应时被多次调用
  • 好吧,你应该将核心数据函数包装在执行块中。 self.managedObjectContext.perform { }
猜你喜欢
  • 2015-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-08
  • 1970-01-01
相关资源
最近更新 更多