iOS Core Data - 如何避免同时保存多个上下文时崩溃?

Posted

技术标签:

【中文标题】iOS Core Data - 如何避免同时保存多个上下文时崩溃?【英文标题】:iOS Core Data - How to avoid crash when many context save at same time? 【发布时间】:2017-10-21 06:02:13 【问题描述】:

当多个上下文同时保存时,我尽量避免崩溃。

以下类有一个操作队列,同时只操作一项工作。它具有三个上下文。首先,defaultContext 是主队列类型,它不直接更新,只对用户可见。另外两个上下文是localContext和externalContext。

LocalContext 用于用户的日程添加,外部 Context 用于外部日程更新,如云同步。本地上下文和外部上下文是 defaultContext 的子级,并将它的自动MergesChangesFromParent 属性设置为 true。即使同时执行用户更新和外部更新。由于它们在同一个队列中按顺序运行,因此不会丢失数据。

当数据输入很小的时候效果很好。但是当数据过多时,应用程序会变慢。有没有更好的方法?

这是我的代码。

class DataController 

    static let shared = DataController()

    var schedules: [Schedule] = []

    var persistentContainer: NSPersistentContainer

    let persistentContainerQueue = OperationQueue()

    private init() 
        persistentContainerQueue.maxConcurrentOperationCount = 1

        persistentContainer = NSPersistentContainer(name: "CoreDataConcurrency")
        persistentContainer.loadPersistentStores  (description, error) in
            if let error = error 
                fatalError("Failed to load Core Data stack: \(error)")
            
        
    

    lazy var defaultContext: NSManagedObjectContext = 
        [unowned self] in
        self.persistentContainer.viewContext
    ()

    lazy var localContext: NSManagedObjectContext = 
        [unowned self] in
        let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        context.parent = self.defaultContext
        context.automaticallyMergesChangesFromParent = true
        return context
    ()

    lazy var externalContext: NSManagedObjectContext = 
        [unowned self] in
        let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        context.parent = self.defaultContext
        context.automaticallyMergesChangesFromParent = true
        return context
    ()

    func enqueueCoreDataOperation(context: NSManagedObjectContext, changeBlock: @escaping () -> (NSManagedObjectContext)) 
        persistentContainerQueue.addOperation 
            let changedContext = changeBlock()

            guard changedContext.hasChanges else 
                return
            

            changedContext.performAndWait(
                do 
                    try changedContext.save()

                    if let parentContext = changedContext.parent 
                        do 
                            try parentContext.save()
                         catch 
                            fatalError()
                        
                    
                 catch 
                    fatalError()
                
            )
        
    

    func addSchedule(title: String, date: Date, context: NSManagedObjectContext) 
        let changeBlock: () -> (NSManagedObjectContext) = 
            let schedule = NSEntityDescription.insertNewObject(forEntityName: "Schedule", into: context) as! Schedule

            schedule.title = title
            schedule.date = date

            return context
        

        enqueueCoreDataOperation(context: context, changeBlock: changeBlock)
    

    func updateSchedule(schedule: Schedule, modifiedTitle: String, context: NSManagedObjectContext) 

        let scheduleInContext = context.object(with: schedule.objectID) as! Schedule

        let changeBlock: () -> (NSManagedObjectContext) = 
            scheduleInContext.title = modifiedTitle

            return context
        

        enqueueCoreDataOperation(context: context, changeBlock: changeBlock)
    

【问题讨论】:

【参考方案1】:

您可以将传入的数据分批成更小的批次,这样每个操作花费的时间更少,并为这些操作添加优先级,这样基于云的更改具有较低的优先级。然后他们将不再阻止其他更改。但我强烈怀疑您在导入操作中做错了事情,导致耗时过长。您是否正在为每个导入的实体进行提取?请分享该代码。

【讨论】:

这是我的全部代码。 github.com/sohn126/CoreDataConcurrency 我在“viewDidAppear”中将大量数据同时强制到两个上下文中。在这种情况下,滚动表格视图时 UI 响应会变慢。

以上是关于iOS Core Data - 如何避免同时保存多个上下文时崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

iOS:Core Data Merge 策略如何影响 NSManagedObjectContext 保存和刷新操作

更新 iOS Core Data 版本以避免崩溃

iOS开发过程中使用Core Data应避免的十个错误

Core Data Fetch 在插入实体时保存关系(同时)

在 iOS 的 Core Data 中建模一对多关系

Swift 3 Core Data - 如何同步保存上下文?