Многочисленные проблемы контекста. Невозможно создать две очереди (основную и личную) для сохранения данных в Core Data. - PullRequest
0 голосов
/ 21 июня 2019

Я хочу настроить сохранение данных в частной очереди ManagedObjectContext, но не могу сделать это правильно.

Я сохранил данные с одним контекстом в mainThread, и он работал нормально. Но после того, как я добавил функции .perform () и executeAndWait () , я не могу получить свои данные в 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 file:

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

Что я не так сделал?

Ответы [ 2 ]

0 голосов
/ 22 июня 2019

Это было довольно просто.Функция saveContext () из CoreDataManager.swift file:

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

Я откладываю privateContext.perform () из managedContext.performAndWait () блок.Более того, я изменил CoreDataManager.instance.persistentContainer.viewContext на CoreDataManager.instance.managedContext , который является моим контекстом (ленивая переменная) И это работает!:)

0 голосов
/ 21 июня 2019

С первого взгляда кажется, что ваши контексты задом наперед. Ваш основной объектный контекст должен быть тем, который вы сохраняете в асинхронном режиме, а частный контекст в частной очереди должен синхронно сохранять. Попробуйте что-то вроде этого:

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

Возможно, это не ваша точная проблема, но если у вас все еще есть проблемы, вам может потребоваться опубликовать больше кода re: ровно какой контент вы сохраняете.

(Кроме того, не выбрасывайте fatalError() в случае сбоя сохранения. Сбой приложения - не лучший UX - лучше проинформировать пользователя и / или повторить попытку сохранения.)

...