保存子上下文时获取NSFetchedResultsController的批量更新

时间:2016-03-07 16:08:17

标签: ios swift uitableview core-data nsfetchedresultscontroller

我有两个私有NSManagedObject上下文,用于处理在后台线程上异步更新Core Data实体,在更新这些上下文后,它们保存到主线程的主上下文中。那时,如果有很多更新,我的主要上下文和NSFetchedResultsController会受到更新的攻击。有没有办法批量执行此操作?

我尝试发送通知,使用委托等,其中数据在子上下文中更新,并且它们按预期工作,但在主要上下文保存操作发生之前都会在后台线程上触发。

我认为理想情况下,我希望在“大”保存正在进行时分离代理,在完成时以某种方式得到通知,执行异步提取请求并在请求完成时在表上调用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

    }
}

1 个答案:

答案 0 :(得分:1)

考虑更改您的上下文配置。您可以直接在持久性存储协调器之上创建背景上下文,而不是创建主队列上下文的子上下文。主要背景也是如此。 现在,当您导入数据并保存在后台上下文中时,您的数据将通过psc写入sql层。在之前的设置中,后台上下文将保存到其父级,这是主要上下文。 为了将更改从后台上下文传播到main,请侦听nsmanagedobjectcontextdidsave通知。然后,您可以将背景上下文中的更改合并到main中。这将减少税收。然而,取决于获取请求。务必尽可能地优化这一点。

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

祝你好运