iOS核心数据 - 如何避免许多上下文在同一时间保存时崩溃?

问题描述:

当许多上下文同时保存时,我会尽量避免崩溃。iOS核心数据 - 如何避免许多上下文在同一时间保存时崩溃?

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

LocalContext用于用户的计划添加,外部上下文用于外部计划更新,如云同步。本地上下文和外部上下文是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) 
    } 
} 

你可以批了输入的数据为较小的批次使每个操作花费更少的时间和优先级添加到操作,使基于云的变化具有较低的优先级。然后他们将不再阻止其他变化。但是我强烈怀疑你在导入操作中做了太多错误的操作。你是否为每个导入的实体进行提取?请分享该代码。

+0

这是我的整个代码。 https://github.com/sohn126/CoreDataConcurrency 我在'viewDidAppear'中同时强制大量数据放入两个上下文中。在这种情况下,滚动表视图时UI响应较慢。 – Sohn