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

时间:2017-10-21 06:02:14

标签: ios swift core-data concurrency

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

以下类有一个操作队列,它只能同时操作一个工作。它有三个背景。首先,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)
    }
}

1 个答案:

答案 0 :(得分:0)

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