我正在使用 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/