CoreData:这个 NSPersistentStoreCoordinator 没有持久存储。它不能执行保存操作
CoreData: This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation
上周我每天遇到一次或两次这个问题,当时我打开我的应用程序并且应用程序尝试对上下文进行任何保存操作,但我仍然找不到重现它的方法。
我在 SO 上搜索了很多问题来解决问题,但大多数都指向 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
之前没有完成,应用程序就会崩溃。
删除后,应用运行正常,没有任何崩溃
上周我每天遇到一次或两次这个问题,当时我打开我的应用程序并且应用程序尝试对上下文进行任何保存操作,但我仍然找不到重现它的方法。
我在 SO 上搜索了很多问题来解决问题,但大多数都指向 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
之前没有完成,应用程序就会崩溃。
删除后,应用运行正常,没有任何崩溃