代码之家  ›  专栏  ›  技术社区  ›  mfaani

当在后台异步保存时,如何保证在嵌套上下文中从不同线程获取的结果是最新的?

  •  1
  • mfaani  · 技术社区  · 7 年前

    我读过以下内容 Behavior differences between performBlock: and performBlockAndWait:? 但没能找到我问题的答案。

    下面的代码来自RayWenderlich video . 特别是在 10:05 代码是 某物

    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)
                }
            }
        }
    }
    

    据我所知,主上下文只是将更改传递给它的父上下文,父上下文是一个私有的背景上下文。它是同步进行的。

    然后父级private context在后台线程中对sqlite执行实际的保存 异步

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

    如何保证我的fetch读取的是最新的和更新的结果?

    如果我们异步写,那么是否有可能同时进行另一次读取,最终会产生意外的结果,即保存更改的结果可能存在,也可能不存在?

    编辑:

    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)
            }
        }
    }
    
    0 回复  |  直到 7 年前
        1
  •  0
  •   jake    7 年前

    所有呼叫 mainManagedObjectContext saveMainContext() 然后马上打电话 mainManagedObjectedContext.fetch(fetchrequest)

    当您执行一个获取请求时,您并没有从持久存储中提取数据- . 您不需要等待更改提交到持久性存储,因为您不需要从那里访问数据。子容器将为您提供最新的更改。

    子容器 容器—它将保存内存中的最新更改(而不是存储在磁盘上—这是持久容器的工作)。

    真正的问题是你的 CoreDataStack CoreDataStack() ,您正在创建一个新的 savingContext mainManagedObjectedContext

    相反,只实例化一次。

    class CoreDataStack {
    
        var coordinator: NSPersistentStoreCoordinator
    
        public static let sharedInstance = CoreDataStack()
    
        private override init() {
            self.coordinator = NSPersistantStoreCoordinator()
        }
    
        ...
        rest of your code here
        ...
    }
    

    CoreDataStack.sharedInstance.saveMainContext()

    (见 this link re:'子对象与父对象是否相同?')

        2
  •  0
  •   mfaani    6 年前

    这个问题并不针对核心数据。

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

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

    coredataManager 将从串行队列访问。因此,即使第2行的写入是异步完成的,第3行的读取也必须等到 序列号