本文介绍了当在后台异步完成保存时,如何保证嵌套上下文中不同线程的获取结果是最新的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已阅读以下。具体在上,代码是某物,如下所示:

The following code is picked up from an RayWenderlich video. Specifically at 10:05 the code is something like this:

class CoreDataStack {
    var coordinator : NSPersistentStoreCoordinator

    init(coordinator: NSPersistentStoreCoordinator){
        self.coordinator = coordinator
    }
    // private, parent, in background used for saving
    private lazy var savingContext : NSManagedObjectContext = {
        let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        moc.persistentStoreCoordinator = coordinator
        return moc
    }()

    lazy var mainManagedObjectedContext : NSManagedObjectContext = {
        let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        moc.parent = self.savingContext
        return moc
    }()

    func saveMainContext() {
        guard savingContext.hasChanges || mainManagedObjectedContext.hasChanges else {
            return
        }

        mainManagedObjectedContext.performAndWait {
            do {
                try mainManagedObjectedContext.save()
            }catch let error{
                fatalError(error.localizedDescription)
            }
        }

        savingContext.perform {
            do {
                try self.savingContext.save()
            }catch let error{
                fatalError(error.localizedDescription)
            }
        }
    }
}

据我了解,会发生什么情况是主上下文只是将更改传递给其父上下文(即私有背景上下文)。它同步执行此操作。

From what I understand what happens is that the main context just passes the changes to its parent context which is a private, background context. It does this synchronously.

然后,父级(私有上下文)在异步后台线程中对sqlite进行实际保存。长话短说,这对我们的表现有很大帮助。但是数据完整性呢?!

Then the parent, private context, does the actual saving against sqlite in a background thread asynchronously. Long story short this helps us a lot with performance. But what about data integrity?!

想象一下我是否要这样做:

Imagine if I was to do this:

let coredataManager = CoreDataStack()
coredataManager.saveMainContext() // save is done asynchronously in background queue
coredataManager.mainManagedObjectedContext.fetch(fetchrequest) 

如何保证我的抓取正在读取最新和更新的结果?

How can I guarantee that my fetch is reading the most recent and updated results?

如果我们异步进行写入,那么是否不可能同时进行另一次读取会导致意外结果,即保存更改的结果可能存在或不存在?

If we do our writes asynchronously then isn't there a chance that another read at the same time could end up with unexpected results ie results of the save changes could or could not be there?

编辑:
我对以下代码进行了改进。我可以将保存内容输入completenessHandler参数中。但这并不能解决整个问题。如果我是从mainQueue发出fetchRequest的,而其他地方却不知道同时进行保存?

I've made an improvement with the code below. I can make my save take in a completionHandler parameter. But that doesn't resolve the entire problem. What if I'm making a fetchRequest from a mainQueue somewhere else that isn't aware that a save is happening at the same time?

enum SaveStatus{
    case noChanges
    case failure
    case success
}


func saveMainContext(completionHandler: (SaveStatus -> ())) {
    guard savingContext.hasChanges || mainManagedObjectedContext.hasChanges else {
        completionHandler(.noChanges)
        return
    }

    mainManagedObjectedContext.performAndWait {
        do {
            try mainManagedObjectedContext.save()
        }catch let error{
            completionHandler(.failure)
            fatalError(error.localizedDescription)
        }
    }

    savingContext.perform {
        do {
            try self.savingContext.save()
            completionHandler(.succes)
        }catch let error{
            completionHandler(.failure)
            fatalError(error.localizedDescription)
        }
    }
}


推荐答案

该问题并非特定于核心数据。

The question isn't specific to core-data.

这是经典的读写问题。

保护数据源的常用方法是访问数据源使用序列队列。否则,如果没有串行队列,您将遇到读写问题。

The common approach with protecting a datasource is to access your datasource using a serial queue. Otherwise yeah without the serial queue you will have a read-write problem.

在以下示例中:

let coredataManager = CoreDataStack() // 1
coredataManager.saveMainContext() // 2 save is done asynchronously in background queue
coredataManager.mainManagedObjectedContext.fetch(fetchrequest) // 3

coredataManager 要从串行队列访问。因此,即使第二行的写入操作是异步完成的,第3行的读取操作也必须等到 serial 队列被解除阻塞。

coredataManager is to be accessed from a serial queue. So even if the write in the 2nd line is done asynchronously, the read at line 3, will have to wait until the serial queue is unblocked.

这篇关于当在后台异步完成保存时,如何保证嵌套上下文中不同线程的获取结果是最新的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 08:52