保存子上下文时获取 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 通知。然后,您可以将后台上下文中的更改合并到主上下文中。这样会减轻负担。然而,有点取决于获取请求。确保尝试尽可能优化它。

查看文档:https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/

祝你好运