保存子上下文时获取 NSFetchedResultsController 的批量更新
Get batch update for NSFetchedResultsController when child contexts are saved
我有两个私有 NSManagedObject 上下文,它们处理在后台线程上异步更新核心数据实体,这些上下文更新后,它们保存到主线程上的主上下文中。那时,如果有很多更新,我的主上下文和 NSFetchedResultsController 就会被更新冲击。有没有办法批量执行此操作?
我曾尝试发送通知、使用委托等,其中数据在子上下文中更新并且它们按预期工作,但在主上下文保存操作发生之前所有操作都在后台线程上触发。
我认为理想情况下我想在 "big" 保存正在进行时分离委托,在完成时以某种方式得到通知,执行异步获取请求并在 table 上调用 reloadData请求已完成。
我有一个 UITableView 和一个 NSFetchedResultsController 使用 UIViewController 上的主上下文:
let fetchRequest = NSFetchRequest(entityName: Message)
fetchRequest.predicate = NSPredicate(format: "groupId == %@", self.groupId)
let idSort = NSSortDescriptor(key: "id", ascending: true)
fetchRequest.sortDescriptors = [idSort]
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil)
do {
try self.fetchedResultsController.performFetch()
} catch {
print("error fetch")
}
self.fetchedResultsController.delegate = self
然后我使用 NSFetchedResultsController 提供的委托:
func controllerWillChangeContent(controller: NSFetchedResultsController) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.tableView?.beginUpdates()
}
}
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
switch type {
case .Insert:
self.tableView?.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Automatic)
self.newIndexPath = newIndexPath
case .Delete:
self.tableView?.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
case .Update:
return
case .Move:
self.tableView?.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
self.tableView?.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Automatic)
}
}
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.tableView?.endUpdates()
// Scroll the table view
if self.newIndexPath != nil {
self.messagesTable?.scrollToRowAtIndexPath(self.newIndexPath!, atScrollPosition: .Bottom, animated: false)
self.newIndexPath = nil
}
}
}
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
let indexSet = NSIndexSet(index: sectionIndex)
switch type {
case .Insert:
self.tableView!.insertSections(indexSet, withRowAnimation: .Automatic)
case .Delete:
self.tableView!.deleteSections(indexSet, withRowAnimation: .Automatic)
default:
break
}
}
考虑更改上下文配置。您可以直接在持久存储协调器之上创建后台上下文,而不是创建主队列上下文的子上下文。主要上下文也是如此。
现在,当您导入数据并保存在后台上下文中时,您的数据将通过 psc 写入 sql 层。在您之前的设置中,背景上下文将保存到它们的父级,这是主要上下文。
为了将更改从后台上下文传播到主要上下文,请监听 nsmanagedobjectcontextdidsave 通知。然后,您可以将后台上下文中的更改合并到主上下文中。这样会减轻负担。然而,有点取决于获取请求。确保尝试尽可能优化它。
祝你好运
我有两个私有 NSManagedObject 上下文,它们处理在后台线程上异步更新核心数据实体,这些上下文更新后,它们保存到主线程上的主上下文中。那时,如果有很多更新,我的主上下文和 NSFetchedResultsController 就会被更新冲击。有没有办法批量执行此操作?
我曾尝试发送通知、使用委托等,其中数据在子上下文中更新并且它们按预期工作,但在主上下文保存操作发生之前所有操作都在后台线程上触发。
我认为理想情况下我想在 "big" 保存正在进行时分离委托,在完成时以某种方式得到通知,执行异步获取请求并在 table 上调用 reloadData请求已完成。
我有一个 UITableView 和一个 NSFetchedResultsController 使用 UIViewController 上的主上下文:
let fetchRequest = NSFetchRequest(entityName: Message)
fetchRequest.predicate = NSPredicate(format: "groupId == %@", self.groupId)
let idSort = NSSortDescriptor(key: "id", ascending: true)
fetchRequest.sortDescriptors = [idSort]
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil)
do {
try self.fetchedResultsController.performFetch()
} catch {
print("error fetch")
}
self.fetchedResultsController.delegate = self
然后我使用 NSFetchedResultsController 提供的委托:
func controllerWillChangeContent(controller: NSFetchedResultsController) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.tableView?.beginUpdates()
}
}
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
switch type {
case .Insert:
self.tableView?.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Automatic)
self.newIndexPath = newIndexPath
case .Delete:
self.tableView?.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
case .Update:
return
case .Move:
self.tableView?.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
self.tableView?.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Automatic)
}
}
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.tableView?.endUpdates()
// Scroll the table view
if self.newIndexPath != nil {
self.messagesTable?.scrollToRowAtIndexPath(self.newIndexPath!, atScrollPosition: .Bottom, animated: false)
self.newIndexPath = nil
}
}
}
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
let indexSet = NSIndexSet(index: sectionIndex)
switch type {
case .Insert:
self.tableView!.insertSections(indexSet, withRowAnimation: .Automatic)
case .Delete:
self.tableView!.deleteSections(indexSet, withRowAnimation: .Automatic)
default:
break
}
}
考虑更改上下文配置。您可以直接在持久存储协调器之上创建后台上下文,而不是创建主队列上下文的子上下文。主要上下文也是如此。 现在,当您导入数据并保存在后台上下文中时,您的数据将通过 psc 写入 sql 层。在您之前的设置中,背景上下文将保存到它们的父级,这是主要上下文。 为了将更改从后台上下文传播到主要上下文,请监听 nsmanagedobjectcontextdidsave 通知。然后,您可以将后台上下文中的更改合并到主上下文中。这样会减轻负担。然而,有点取决于获取请求。确保尝试尽可能优化它。
祝你好运