使用带有 NSBatchDeleteRequest 的 NSFetchedResultsController
Posted
技术标签:
【中文标题】使用带有 NSBatchDeleteRequest 的 NSFetchedResultsController【英文标题】:Using NSFetchedResultsController w/NSBatchDeleteRequest 【发布时间】:2016-11-13 15:11:29 【问题描述】:我在使用 NSBatchDeleteRequest 后从 NSFetchedResultsControllerDelegate 获取准确更新时遇到问题,更改是作为更新类型而不是 didChange 委托方法上的删除类型来实现的。有没有办法让更改作为删除进入? (我有不同的删除和更新场景)。
删除请求: (使用调用者提供的私有上下文)
fileprivate class func deletePeopleWith(ids: Set<Int>, usingContext context: NSManagedObjectContext)
let fr: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Person")
var predicates: [NSPredicate] = []
ids.forEach
predicates.append(NSPredicate(format: "id = %ld", $0))
fr.predicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
let dr = NSBatchDeleteRequest(fetchRequest: fr)
dr.affectedStores = context.parent?.persistentStoreCoordinator?.persistentStores
do
try context.parent?.execute(dr)
context.parent?.refreshAllObjects()
print("Deleting person")
catch let error as NSError
let desc = "Could not delete person with batch delete request, with error: \(error.localizedDescription)"
debugPrint(desc)
结果:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
DispatchQueue.main.async
let changeDesc = "Have change with indexPath of: \(indexPath), new index path of: \(newIndexPath) for object: \(anObject)"
var changeType = ""
switch type
case .delete:
changeType = "delete"
case .insert:
changeType = "insert"
case .move:
changeType = "move"
case .update:
changeType = "update"
print(changeDesc)
print(changeType)
印刷:
Have change with indexPath of: Optional([0, 0]), new index path of: Optional([0, 0]) for object: *my core data object*
update
【问题讨论】:
您正在父上下文上执行删除,并且您说要使用提供的私有上下文进行删除。 @ELKA 获取的结果控制器是使用父上下文创建的,父上下文也是上下文,其父上下文是应该删除记录的持久存储。 因此 context.parent 将是一个主要的 NSManagedObjectContext ,它与 NSFetchedResultController 的上下文相同。对吗? @ELKA 是的,就是这样。 你可以试试context.parent?.processPendingChanges()
而不是refreshAllObjects()
【参考方案1】:
来自苹果的documentation:
批量删除比您自己在代码中删除核心数据实体运行得更快,因为它们在 SQL 级别的持久存储本身中运行。作为这种差异的一部分,对持久存储进行的更改不会反映在当前内存中的对象中。
执行批量删除后,删除内存中已从持久存储中删除的所有对象。
请参阅Updating Your Application After Execution 部分以处理由NSBatchDeleteRequest
删除的对象。
【讨论】:
单独的文档不起作用,但在删除请求中将结果类型更新为对象 ID,然后在获取的结果控制器使用的上下文中调用刷新所有对象,使更改以删除的形式出现! 文档没有明确显示代码,但它确实声明:“要做到这一点,首先确保NSBatchDeleteRequest
的 resultType
设置为 NSBatchDeleteRequestResultType.resultTypeObjectIDs
之前请求被执行。”所以一定要包括:deleteRequest.resultType = .resultTypeObjectIDs
.
非常感谢,这正是我想要的!【参考方案2】:
这是示例,对我有用。但我没有找到如何使用动画更新删除,因为NSFetchedResultsControllerDelegate
没有触发。
@IBAction func didPressDelete(_ sender: UIBarButtonItem)
let managedObjectContext = persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: Record.self))
let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
do
// delete on persistance store level
try managedObjectContext.execute(deleteRequest)
// reload the whole context
managedObjectContext.reset()
try self.fetchedResultsController.performFetch()
tableV.reloadData()
catch
print("?")
Thanks.
【讨论】:
【参考方案3】:由于NSBatchDeleteRequest
删除了persistentStore 级别的托管对象(在磁盘上),因此更新当前上下文(在内存中)的最有效方法是在上下文中调用refreshAllObjects()
,如下所示:
func batchDelete()
if let appDelegate = UIApplication.shared.delegate as? AppDelegate
let context = appDelegate.persistentContainer.viewContext
if let request = self.fetchedResultsController.fetchRequest as? NSFetchRequest<NSFetchRequestResult>
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: request)
do
try context.execute(batchDeleteRequest) // performs the deletion
appDelegate.saveContext()
context.refreshAllObjects() // updates the fetchedResultsController
catch
print("Batch deletion failed.")
无需重新获取所有对象或tableView.reloadData()
!
【讨论】:
我认为应遵循已接受答案中链接的文档,我的原始评论/问题已刷新所有对象,但这些天的方法是将更改合并到目标上下文中(s ) 来自删除请求的结果。以上是关于使用带有 NSBatchDeleteRequest 的 NSFetchedResultsController的主要内容,如果未能解决你的问题,请参考以下文章
核心数据 NSBatchDeleteRequest 似乎将对象留在上下文中
如何设置 NSBatchDeleteRequest 的 NSBatchDeleteResult 类型?
UI 在执行 NSBatchDeleteRequest 时冻结