多上下文麻烦。无法在 Core Data 中创建两个队列(主队列和私有队列)保存数据

Posted

技术标签:

【中文标题】多上下文麻烦。无法在 Core Data 中创建两个队列(主队列和私有队列)保存数据【英文标题】:Multiple context trouble. Can't make two queues (main and private) save data in Core Data 【发布时间】:2019-06-21 17:45:07 【问题描述】:

我想在 ManagedObjectContext 的私有队列上设置保存数据,但无法正确执行。

我已经在 mainThread 中使用一个上下文保存了数据,它工作正常。但是当我添加 .perform()performAndWait() 函数后,我无法在 SQLite 中获取我的数据。

我在 CoreDataManager.swift 文件中有这个功能:

func saveContext() 
        privateObjectContext.perform 
            do 
                try self.privateObjectContext.save()
                self.mainObjectContext.performAndWait 
                    do 
                        try self.mainObjectContext.save()
                     catch 
                        fatalError("Failure to save context: \(error)")
                    
                
             catch 
                fatalError("Failure to save context: \(error)")
            
        

并从 Repository.swift 文件中调用此函数:

func insertQuestProgress(qp: QuestProgress) 
        //here's my code
        CoreDataManager.instance.saveContext()
    

同样在 CoreDataManager.swift 文件中,我初始化了 privateContext 和 mainContext 的变量,就像在关于这个主题的大量文章中一样:

private lazy var privateObjectContext: NSManagedObjectContext = 
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        managedObjectContext.parent = self.mainObjectContext
        return managedObjectContext
    ()

    private lazy var mainObjectContext: NSManagedObjectContext = 
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        managedObjectContext.persistentStoreCoordinator = CoreDataManager.instance.persistentContainer.persistentStoreCoordinator
        return managedObjectContext
    ()

也许它不保存,因为在 insertQuestProgress(qp: QuestProgress) 我创建了具有 CoreDataManager.instance.persistentContainer.viewContext

上下文的新实体
func deleteQuestProgress(id: String) 
        let questProgresses = CoreDataManager.instance.fetchQuestprogress()
        guard let questProgress = questProgresses.first(where: $0.questId == id) else return
        CoreDataManager.instance.persistentContainer.viewContext.delete(questProgress)
        CoreDataManager.instance.saveContext()
    

    func insertQuestProgress(qp: QuestProgress) 
        if let quest = getQuestProgressEntityById(id: qp.questId)
            quest.qpJson = converter.toJson(value: qp)
        
        else
            let questProgress = QuestProgressEntity(context: CoreDataManager.instance.persistentContainer.viewContext)
            questProgress.questId = qp.questId
            questProgress.qpJson = converter.toJson(value: qp)
        
        CoreDataManager.instance.saveContext()
    

我做错了什么?

【问题讨论】:

【参考方案1】:

乍一看,您的上下文似乎倒退了。您的主要对象上下文应该是您异步保存的对象,而私有队列上的私有上下文应该同步保存。试试这样的:

    // Parent context, will save things on a private queue synchronously.
    private lazy var privateContext: NSManagedObjectContext = 
        let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        moc.persistentStoreCoordinator = coordinator
        return moc
    ()

    // Child context, should be used asynchronously.
    private(set) lazy var managedContext: NSManagedObjectContext = 
        let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        moc.parent = privateContext
        return moc
    ()

    func saveContext() 
        mainObjectContext.perform 
            do 
                try self.mainObjectContext.save()
                self.privateObjectContext.performAndWait 
                    do 
                        try self.privateObjectContext.save()
                     catch 
                        print("Failure to save context: \(error)")
                    
                
             catch 
                print("Failure to save context: \(error)")
            
        

这可能不是您的确切问题,但如果您仍然遇到问题,您可能需要发布更多代码:确切地 what 内容是您保存。

(另外,如果您的保存失败,请考虑不要抛出 fatalError()。崩溃您的应用并不是很好的用户体验 - 最好通知用户和/或重试保存。)

【讨论】:

【参考方案2】:

这很简单。 CoreDataManager.swift 文件中的函数 saveContext()

func saveContext() 
        managedContext.performAndWait 
            do 
                try self.managedContext.save()
             catch 
                print("Failure to save context: \(error)")
            
        
        privateContext.perform 
            do 
                try self.privateContext.save()
             catch 
                print("Failure to save context: \(error)")
            
        
    

我从 ma​​nagedContext.performAndWait() 块中推迟了 privateContext.perform()。 此外,我将 CoreDataManager.instance.persistentContainer.viewContext 更改为 CoreDataManager.instance.managedContext 这是我的上下文(惰性变量) 它有效! :)

【讨论】:

以上是关于多上下文麻烦。无法在 Core Data 中创建两个队列(主队列和私有队列)保存数据的主要内容,如果未能解决你的问题,请参考以下文章

尝试在react-native中创建两列

Core Data 多上下文唯一性

如何在 Django 中创建两种类型的用户?

将主上下文和私有上下文与 Core Data 合并

当应用程序后台运行时,Core Data 无法通过区域监控保存上下文

Core Data 托管对象上下文线程同步