【问题标题】:Unable to destroy persistent store created with Core Data and SQLite无法销毁使用 Core Data 和 SQLite 创建的持久存储
【发布时间】:2019-01-30 09:26:57
【问题描述】:

我有一个 iOS 应用程序,我想在每次启动时从一个新的 Core Data 数据库开始。商店类型是 SQLite。

但是,当我调用 persistentStoreCoordinator.destroyPersistentStore() 时,我 100% 都会收到错误。

代码如下:

func destroyPersistentStore() {
    guard let modelURL = Bundle.main.url(forResource: self.modelName, withExtension: "momd") else {
        print("Missing data model - could not destroy")
        return
    }

    do {
        try persistentStoreCoordinator.destroyPersistentStore(at: modelURL, ofType: storeType, options: nil)
    } catch  {
        print("Unable to destroy persistent store: \(error) - \(error.localizedDescription)")
   }
}

错误是:

无法销毁持久存储:错误域=NSSQLiteErrorDomain Code=14 "(null)" UserInfo={NSFilePath=.../AppName.app/ModelName.momd, 原因=无法截断数据库} - 无法执行该操作 完全的。 (NSSQLiteErrorDomain 错误 14。)

即使出现此错误,该应用仍能够保存和访问商店中的数据。问题是每次启动时都会加载初始数据,从而创建重复项。

下面是调用destroyPersistentStore的地方:

  1. SQLite 数据文件肯定存在并包含数据
  2. 发生在模拟器或真实设备上
  3. modelUrl 是正确的,并且指向了 momd
  4. 存储类型为 SQLite
  5. SQLite 数据文件保存在 Documents 目录中
  6. persistentStoreCoordinator.url(for: persistentStoreCoordinator.persistentStores.first!) 指向 Documents 目录中的文件。

我在网上搜索了答案,找不到任何人报告这个错误,但我在这个项目和一个简化的演示项目中都有这个错误。我根本无法让 destroyPersistentStore 工作。

最后,当我暂停执行并 po 到 persistentStoreCoordinator.managedObjectModel 时,第一行是:

po persistentStoreCoordinator.managedObjectModel () isEditable 0, 实体...

isEditable 问题可能是问题所在吗?我将如何改变它?

【问题讨论】:

    标签: ios swift core-data


    【解决方案1】:

    您正在合并 Core Data 堆栈中的两个对象:

    • model 位于您的应用程序包中,具有扩展名 .momd,并包含有关您的 Core Data 对象定义的信息:您拥有哪些实体、它们具有哪些属性、它们的关系等等开。
    • persistent store 是应用容器中的数据文件(不在捆绑包中)。您在创建或加载持久存储时定义其 URL。它包含模型对象的实际实例的数据,而不是抽象定义。

    我认为您想要获取持久存储的 URL,而不是获取模型的 URL。您可以通过查看持久存储协调器的 persistentStores 数组、选择一个并获取其 URL 来做到这一点:

    func destroyPersistentStore() {
        guard let firstStoreURL = persistentStoreCoordinator.persistentStores.first?.url else {
            print("Missing first store URL - could not destroy")
            return
        }
    
        do {
            try persistentStoreCoordinator.destroyPersistentStore(at: firstStoreURL, ofType: storeType, options: nil)
        } catch  {
            print("Unable to destroy persistent store: \(error) - \(error.localizedDescription)")
       }
    }
    

    这会破坏第一家商店;如果您有多个,则可以改为遍历持久性存储,将它们全部销毁,具体取决于您的应用程序的要求。

    【讨论】:

    • 谢谢。一直在拔掉我剩下的头发!
    【解决方案2】:

    iOS 15 版本

    // function to delete persistent store
    
    func deletePersistentStore() {
        let coordinator = self.persistentContainer.persistentStoreCoordinator
        guard let store = coordinator.persistentStores.first else {
            return
        }
        let storeURL = coordinator.url(for: store)
        do {
            if #available(iOS 15.0, *) {
                let storeType: NSPersistentStore.StoreType = inMemoryStore ? .inMemory : .sqlite
                try coordinator.destroyPersistentStore(at: storeURL, type: storeType)
            } else {
                let storeType: String = inMemoryStore ? NSInMemoryStoreType : NSSQLiteStoreType
                try coordinator.destroyPersistentStore(at: storeURL, ofType: storeType)
                try coordinator.addPersistentStore(ofType: storeType, configurationName: nil, at: storeURL, options: nil)
            }
        }
        catch {
            print(error.localizedDescription)
        }
    }
    

    【讨论】:

      【解决方案3】:

      找到了这个很棒的解决方案:

      import Foundation
      import CoreData
      
      extension NSManagedObjectContext
      {
          func deleteAllData()
          {
              guard let persistentStore = persistentStoreCoordinator?.persistentStores.last else {
                  return
              }
      
              guard let url = persistentStoreCoordinator?.url(for: persistentStore) else {
                  return
              }
      
              performAndWait { () -> Void in
                  self.reset()
                  do
                  {
                      try self.persistentStoreCoordinator?.remove(persistentStore)
                      try FileManager.default.removeItem(at: url)
                      try self.persistentStoreCoordinator?.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
                  }
                  catch { /*dealing with errors up to the usage*/ }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-15
        • 2012-12-14
        • 1970-01-01
        • 2015-02-14
        • 1970-01-01
        • 2012-09-10
        • 1970-01-01
        相关资源
        最近更新 更多