ios - 核心数据更新旧项目,创建新记录

标签 ios swift core-data cloudkit

我正在使用 iOS 9/Xcode 7/Swift 2 构建一个 iOS 应用

主要的数据存储是 Cloudkit,它工作正常(但速度很慢)并且允许在用户之间共享数据。

为了加快大多数查询的处理速度,Core Data 在本地使用。

更新核心数据时,会出现两种状态—— 1. 一条新记录从 CloudKit 添加到核心数据(这似乎工作正常) 2. 从 CloudKit 更新现有的 Core Data 记录(这是有问题的步骤!)

是应该删除现有的 Core Data 记录,然后创建一个新记录,还是其他一些解决方案?

这是到目前为止的代码 -

let entityDescription = NSEntityDescription.entityForName("FoodItem", inManagedObjectContext: self.managedObjectContext)

    let localFoodItem = NSManagedObject(entity: entityDescription!, insertIntoManagedObjectContext: self.managedObjectContext)

    let syncpredicate = NSPredicate(value: true)

    let syncquery = CKQuery(recordType: "Food", predicate: syncpredicate)

publicDatabase.performQuery(syncquery, inZoneWithID: nil) { results, error in
        if error == nil { // There is no error
            var numberAdded = 0
            for entry in results! {

                let cloudUPC = entry["UPC"] as? String
                //print("UPC from CloudKit \(cloudUPC)")
                let cloudFoodName = entry["foodName"] as? String
                //print("Name from CloudKit \(cloudFoodName)")
                let cloudIngredients = entry["ingredients"] as? String
                //print("Ingredients from CloudKit \(cloudFoodName)")
                numberAdded++


                let corepredicate = NSPredicate(format: "upc = %@", cloudUPC!)


                // Initialize Fetch Request
                let fetchRequest = NSFetchRequest()

                fetchRequest.predicate = corepredicate
                fetchRequest.entity = entityDescription

                var error: NSError?

                do {
                    let result = try self.managedObjectContext.executeFetchRequest(fetchRequest)


                    if result.count > 0 {
                        let match = result[0] as! NSManagedObject
                        print("FoodItem Found in CoreData")
                        let upcNumber = match.valueForKey("upc") as! String


                        let iList = match.valueForKey("ingredients") as! String



                        let coreName = match.valueForKey("productName") as! String

print("Item UPDATED in CoreData")
                            localFoodItem.setValue(cloudUPC, forKey: "upc")
                            localFoodItem.setValue(cloudFoodName, forKey: "productName")
                            localFoodItem.setValue(cloudIngredients, forKey: "ingredients")


                    } else {
                        print("IMPORTED New Item from CloudKit")
                        localFoodItem.setValue(cloudUPC, forKey: "upc")
                        localFoodItem.setValue(cloudFoodName, forKey: "productName")
                        localFoodItem.setValue(cloudIngredients, forKey: "ingredients")
                        //print("Record Update: \(numberAdded)")
                    }


                } catch let error as NSError {
                    // failure
                    print("Fetch failed: \(error.localizedDescription)")
                }


            do {
                try self.managedObjectContext.save()
            } catch {
                print(error)
            }
            }
            print("Database Additions: \(numberAdded)")
        }else {
            print(error)
        }

    }

最佳答案

就是这一行:

let localFoodItem = NSManagedObject(entity: entityDescription!, insertIntoManagedObjectContext: self.managedObjectContext)

创建新的 CoreData 记录。随后的 for 循环的每次迭代只会更改该记录的属性值,因此即使有多个项目要从 CloudKit 同步,也只会创建一个新的 CoreData 记录。上面的行应该在 for 循环中。如果没有预先存在的具有相同 upc 的对象,您只想创建一个新的 CoreData 对象,所以上面的行应该在 else 子句中。如果有一个预先存在的对象,我假设您只想使用来自 CloudKit 的新值更新该对象的其他属性:

let entityDescription = NSEntityDescription.entityForName("FoodItem", inManagedObjectContext: self.managedObjectContext)
let syncpredicate = NSPredicate(value: true)
let syncquery = CKQuery(recordType: "Food", predicate: syncpredicate)
publicDatabase.performQuery(syncquery, inZoneWithID: nil) { results, error in
    if error == nil { // There is no error
        var numberAdded = 0
        var numberUpdated = 0
        for entry in results! {
            let cloudUPC = entry["UPC"] as? String
            //print("UPC from CloudKit \(cloudUPC)")
            let cloudFoodName = entry["foodName"] as? String
            //print("Name from CloudKit \(cloudFoodName)")
            let cloudIngredients = entry["ingredients"] as? String
            //print("Ingredients from CloudKit \(cloudFoodName)")

            let corepredicate = NSPredicate(format: "upc = %@", cloudUPC!)
            // Initialize Fetch Request
            let fetchRequest = NSFetchRequest()
            fetchRequest.predicate = corepredicate
            fetchRequest.entity = entityDescription

            var error: NSError?
            do {
                let result = try self.managedObjectContext.executeFetchRequest(fetchRequest)
                if result.count > 0 {
                    let match = result[0] as! NSManagedObject
                    print("FoodItem Found in CoreData")
                    // The next three lines seem superfluous?
                    let upcNumber = match.valueForKey("upc") as! String
                    let iList = match.valueForKey("ingredients") as! String
                    let coreName = match.valueForKey("productName") as! String
                    print("Item UPDATED in CoreData")
                    match.setValue(cloudFoodName, forKey: "productName")
                    match.setValue(cloudIngredients, forKey: "ingredients")
                    numberUpdated++
                } else {
                    print("IMPORTED New Item from CloudKit")
                    let localFoodItem = NSManagedObject(entity: entityDescription!, insertIntoManagedObjectContext: self.managedObjectContext)
                    localFoodItem.setValue(cloudUPC, forKey: "upc")
                    localFoodItem.setValue(cloudFoodName, forKey: "productName")
                    localFoodItem.setValue(cloudIngredients, forKey: "ingredients")
                    numberAdded++
                }
            } catch let error as NSError {
                // failure
                print("Fetch failed: \(error.localizedDescription)")
            }
        }
        do {
            try self.managedObjectContext.save()
            print("Database Additions: \(numberAdded)")
            print("Database Updates: \(numberUpdated)")
        } catch {
            print(error)
        }
    }else {
        print(error)
    }
}

请注意,我会将 save 操作移动到 for 循环之后,而不是在 for 循环内。此外,如果 CloudKit 完成处理程序未在主线程上执行,您可能会发现 CoreData 线程/并发问题(我不熟悉 CK,因此无法提供建议)。

关于ios - 核心数据更新旧项目,创建新记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34557945/

相关文章:

ios - UITableview 根据所选单元格显示不同的数据

iphone - 不兼容的指针类型将 'NSSortDescriptor *__strong' 发送到 'NSArray * 类型的参数

iphone - 应用ARC后仍然面临内存警告

iphone - performBlock 在哪个线程上运行?

ios - CKRecord 获取返回 1 条 RecordID 为空的记录

ios - 是否可以将 UITableView 子类化为 SKNode?

ios - SKSpriteNode 隐藏在 UI 背景图像下

IOS8 UISearchController 直接显示搜索栏

ios - 如何在 Xcode 6.4 中创建 .dsym 文件

ios - 如何将函数传递给 Swift 中的另一个类