NSFetchedResultsController 加上 NSBatchUpdateRequest 等于 NSMergeConflict。我做错了什么?
NSFetchedResultsController plus NSBatchUpdateRequest equals NSMergeConflict. What do I do wrong?
我使用 NSManagedObjectContext
设置了一个 NSFetchedResultsController
。我使用此上下文执行提取。
我还有一个 NSBatchUpdateRequest
,我使用相同的 NSManagedObjectContext
设置的。我使用相同的 NSManagedObjectContext
.
执行请求
当我使用 NSBatchUpdateRequest
执行请求时,我可以看到我的所有数据都已更新。
如果我重新启动该应用程序,使用 NSFetchedResultsController
的任何提取也会正常工作。
问题是当我没有重新启动应用程序并且我一个接一个地执行这两个操作时,当我从上下文中调用方法 save
时出现 NSMergeConflict (0x17427a900) for NSManagedObject (0x1740d8d40) with objectID '0xd000000001b40000...
错误。
我知道问题来自对同一数据的并发更改,但我不知道解决方案是什么?一个可能是通过 NSMergePolicy
class,但我怀疑这是解决我的问题的一种干净方法。
我该怎么办?有两个不同的上下文? (怎么样?)
好吧,看来我可能已经找到了操作方法,但是如果您发现任何错误,请告诉我。
当您执行批量更新时,您有可能获得更新的行数或更新的对象 ID 列表的结果,无论是否为空。你必须选择最后一个。
从上下文中执行 executeRequest
后,您需要获取对象 ID 列表,循环遍历所有对象以将每个 NSManagedObject
归因于方法 objectWithID
的上下文对象。如果您不知道 Core Data 中的 Faults 对象是什么,here 就是解释。
每获得一个 NSManagedObject
,您就需要使用其方法 refreshObject
刷新上下文。
完成后,您需要再次执行 fetchedResultsController
的 performFetch
以返回到批量更新之前的状态。
如果我哪里错了请告诉我。
代码如下:
let batchUpdate = NSBatchUpdateRequest(entityName: "myEntity")
batchUpdate.propertiesToUpdate = ["myPropertieToUpdate" : currency.amountToCompute]
batchUpdate.affectedStores = managedContext.persistentStoreCoordinator?.persistentStores
batchUpdate.resultType = .UpdatedObjectIDsResultType
var batchError: NSError?
let batchResult = managedContext.executeRequest(batchUpdate, error: &batchError) as NSBatchUpdateResult?
if let result = batchResult {
println("Records updated \((result.result as [NSManagedObjectID]).count)")
// Extract Object IDs
let objectIDs = result.result as [NSManagedObjectID]
for objectID in objectIDs {
// Turn Managed Objects into Faults
let nsManagedObject: NSManagedObject = managedContext.objectWithID(objectID)
if let managedObject = nsManagedObject as NSManagedObject? {
managedContext.refreshObject(managedObject, mergeChanges: false)
}
}
// Perform Fetch
var error: NSError? = nil
if !fetchedResultsController.performFetch(&error) {
println("error: + \(error?.localizedDescription), \(error!.userInfo)")
}
} else {
println("Could not update \(batchError), \(batchError!.userInfo)")
}
编辑:
这里有两个链接以获得更多解释:
http://code.tutsplus.com/tutorials/ios-8-core-data-and-batch-updates--cms-22164
http://www.bignerdranch.com/blog/new-in-core-data-and-ios-8-batch-updating/
我使用 NSManagedObjectContext
设置了一个 NSFetchedResultsController
。我使用此上下文执行提取。
我还有一个 NSBatchUpdateRequest
,我使用相同的 NSManagedObjectContext
设置的。我使用相同的 NSManagedObjectContext
.
当我使用 NSBatchUpdateRequest
执行请求时,我可以看到我的所有数据都已更新。
如果我重新启动该应用程序,使用 NSFetchedResultsController
的任何提取也会正常工作。
问题是当我没有重新启动应用程序并且我一个接一个地执行这两个操作时,当我从上下文中调用方法 save
时出现 NSMergeConflict (0x17427a900) for NSManagedObject (0x1740d8d40) with objectID '0xd000000001b40000...
错误。
我知道问题来自对同一数据的并发更改,但我不知道解决方案是什么?一个可能是通过 NSMergePolicy
class,但我怀疑这是解决我的问题的一种干净方法。
我该怎么办?有两个不同的上下文? (怎么样?)
好吧,看来我可能已经找到了操作方法,但是如果您发现任何错误,请告诉我。
当您执行批量更新时,您有可能获得更新的行数或更新的对象 ID 列表的结果,无论是否为空。你必须选择最后一个。
从上下文中执行 executeRequest
后,您需要获取对象 ID 列表,循环遍历所有对象以将每个 NSManagedObject
归因于方法 objectWithID
的上下文对象。如果您不知道 Core Data 中的 Faults 对象是什么,here 就是解释。
每获得一个 NSManagedObject
,您就需要使用其方法 refreshObject
刷新上下文。
完成后,您需要再次执行 fetchedResultsController
的 performFetch
以返回到批量更新之前的状态。
如果我哪里错了请告诉我。
代码如下:
let batchUpdate = NSBatchUpdateRequest(entityName: "myEntity")
batchUpdate.propertiesToUpdate = ["myPropertieToUpdate" : currency.amountToCompute]
batchUpdate.affectedStores = managedContext.persistentStoreCoordinator?.persistentStores
batchUpdate.resultType = .UpdatedObjectIDsResultType
var batchError: NSError?
let batchResult = managedContext.executeRequest(batchUpdate, error: &batchError) as NSBatchUpdateResult?
if let result = batchResult {
println("Records updated \((result.result as [NSManagedObjectID]).count)")
// Extract Object IDs
let objectIDs = result.result as [NSManagedObjectID]
for objectID in objectIDs {
// Turn Managed Objects into Faults
let nsManagedObject: NSManagedObject = managedContext.objectWithID(objectID)
if let managedObject = nsManagedObject as NSManagedObject? {
managedContext.refreshObject(managedObject, mergeChanges: false)
}
}
// Perform Fetch
var error: NSError? = nil
if !fetchedResultsController.performFetch(&error) {
println("error: + \(error?.localizedDescription), \(error!.userInfo)")
}
} else {
println("Could not update \(batchError), \(batchError!.userInfo)")
}
编辑: 这里有两个链接以获得更多解释:
http://code.tutsplus.com/tutorials/ios-8-core-data-and-batch-updates--cms-22164
http://www.bignerdranch.com/blog/new-in-core-data-and-ios-8-batch-updating/