CoreData: у этого NSPersistentStoreCoordinator нет постоянных хранилищ. Не может выполнить операцию сохранения - PullRequest
0 голосов
/ 14 февраля 2020

Я сталкиваюсь с этой проблемой один или два раза в день в течение последней недели, когда я открываю свое приложение, и приложение пытается выполнить любую операцию сохранения в контексте, я все еще не могу найти способ воспроизвести ее.

Я искал много вопросов по SO для исправления, но большинство из них указывают на проблемы 2

  1. Проблема переноса основных данных (которой у меня нет, так как я использую ту же версию модели, нет .)

  2. сбой при загрузке постоянного хранилища (что также не происходит в моем случае, поскольку мой базовый стек данных не инициализирует основной пользовательский интерфейс, если метод loadPersistentStores включен ошибка persistentContainer)

Я использую настройку стека основных данных, указанную в приведенной ниже ссылке: https://williamboles.me/progressive-core-data-migration/

Вот моя установка CoreData класс:

lazy var persistentContainer: NSPersistentContainer = {

    let persistentContainer = NSPersistentContainer(name: "ABC")
    let description = persistentContainer.persistentStoreDescriptions.first
    description?.shouldInferMappingModelAutomatically = false //inferred mapping will be handled else where
    description?.shouldMigrateStoreAutomatically = false
    description?.type = storeType

    return persistentContainer
}()

lazy var managedObjectContext: NSManagedObjectContext = {
    let context =  self.persistentContainer.newBackgroundContext()
    context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    context.automaticallyMergesChangesFromParent = true

    return context
}()

lazy var _managedObjectContext: NSManagedObjectContext = {
    let context = self.persistentContainer.viewContext
    context.automaticallyMergesChangesFromParent = true

    return context
}()

// MARK: - Singleton

private static var privateShared : CoreDataManager?

class func shared() -> CoreDataManager { // change class to final to prevent override
    guard let uwShared = privateShared else {
        privateShared = CoreDataManager()
        return privateShared!
    }
    return uwShared
}

class func destroy() {
    privateShared = nil
}


// MARK: - Init

init(storeType: String = NSSQLiteStoreType, migrator: CoreDataMigratorProtocol = CoreDataMigrator()) {
    self.storeType = storeType
    self.migrator = migrator
}

// MARK: - SetUp

func setup(completion: @escaping () -> Void) {
    loadPersistentStore {
        completion()
    }
}

// MARK: - Loading

private func loadPersistentStore(completion: @escaping () -> Void) {

    migrateStoreIfNeeded {
        self.persistentContainer.loadPersistentStores { description, error in
            guard error == nil else {
                fatalError("was unable to load store \(error!)")
            }

            completion()
        }
    }
}

private func migrateStoreIfNeeded(completion: @escaping () -> Void) {

    guard let storeURL = persistentContainer.persistentStoreDescriptions.first?.url else {
        fatalError("persistentContainer was not set up properly")
    }

    if migrator.requiresMigration(at: storeURL, toVersion: CoreDataMigrationVersion.current) {
        DispatchQueue.global(qos: .userInitiated).async {
            self.migrator.migrateStore(at: storeURL, toVersion: CoreDataMigrationVersion.current)

            DispatchQueue.main.async {
                completion()
            }
        }
    } else {
        completion()
    }
}

И я инициализирую стек Базовых данных, используя следующий код в делегате приложения:

 CoreDataManager.shared().setup {[unowned self] in

     self.showMainUI()
 }

Мое приложение падает после загрузки контроллера домена и некоторой части моего код выполняет операцию сохранения на определенной модели NSManagedObject

Это способ сохранения в Context:

let context  = CoreDataManager.shared().managedObjectContext // background context
context.performAndWait {
    if let entityDescription = NSEntityDescription.entity(forEntityName: Entity_Name, in: context) {
        if let runEntityObject =  NSManagedObject(entity: entityDescription, insertInto: context) as? MY_Model {

            // Create the Object                    
            guard context.hasChanges else { return }
            do {
                try context.save() // Crashes here once or twice a day :(
            }
            catch {
                print(error.localizedDescription)
            }
        }
    }
}

В некоторых ответах SO также упоминаются проблемы с многопоточностью, но я использую блок executeAndWait, поэтому сохранение происходит в той же очереди

очень полезно, если кто-то указал мне правильное направление по этому вопросу

1 Ответ

0 голосов
/ 18 февраля 2020

После многократного просмотра файла AppDelegate я обнаружил, что выполняю операцию сохранения основных данных в методе applicationDidBecomeActive, который также вызывается при запуске приложения из приостановленного состояния.

Так что если мое закрытие установки стека основных данных не завершилось sh до того, как applicationDidBecomeActive был вызван, приложение взломало бы sh.

После удаления приложение работало нормально без сбоев

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...