CoreData:这个 NSPersistentStoreCoordinator 没有持久存储。它不能执行保存操作

CoreData: This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation

上周我每天遇到一次或两次这个问题,当时我打开我的应用程序并且应用程序尝试对上下文进行任何保存操作,但我仍然找不到重现它的方法。

我在 SO 上搜索了很多问题来解决问题,但大多数都指向 2 个问题

  1. 核心数据迁移问题(我没有,因为我在同一型号版本号上。)

  2. 加载持久存储失败(这在我的情况下也不会发生,因为如果 loadPersistentStores 我的核心数据堆栈没有初始化主 UI persistentContainer 上的方法失败)

我正在使用下面提到的 Core Data 堆栈设置 link: https://williamboles.me/progressive-core-data-migration/

这是我的 CoreData 设置 class:

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

然后我在 App Delegate 中使用以下代码初始化核心数据堆栈:

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

     self.showMainUI()
 }

我的应用程序在 Home Controller 加载后崩溃并且我的部分代码对某些 NSManagedObject 模型执行了保存操作

这是我保存到上下文的方式:

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 答案也提到了线程问题,但我使用的是 performAndWait 块,因此保存发生在同一个队列上

如果有人就此问题向我指出正确的方向,那将会非常有帮助

多次查看我的 AppDelegate 文件后,我发现我在 applicationDidBecomeActive 方法中进行了 Core Data 保存操作,该方法在应用程序从挂起状态启动时也会被调用。

因此,如果我的核心数据堆栈设置闭包在调用 applicationDidBecomeActive 之前没有完成,应用程序就会崩溃。

删除后,应用运行正常,没有任何崩溃