【问题标题】:An error occurring during Core Data persistent store migration in iOS 13iOS 13 中 Core Data 持久存储迁移期间发生的错误
【发布时间】:2020-02-01 13:10:57
【问题描述】:

在将 XCode 更新到版本 11 后,我向 Core Data 添加了一个新模型版本,并在新版本中向实体添加了一个新属性。使新版本处于活动状态并将新属性添加到托管对象文件中。

向用户发布此版本后,它开始崩溃并显示以下消息:“用于打开持久存储的托管对象模型版本与用于创建持久存储的版本不兼容。”和“列名重复 ZNEWCOLUMN”。到目前为止,我对 Core Data 模型进行了很多更改,并且迁移始终有效。

此崩溃仅出现在 iOS 13 上!

这是我加载核心数据的方式:

    lazy var managedObjectContext: NSManagedObjectContext = {

        return self.persistentContainer.viewContext
    }()

    lazy var persistentContainer: NSPersistentContainer = {
        /*
         The persistent container for the application. This implementation
         creates and returns a container, having loaded the store for the
         application to it. This property is optional since there are legitimate
         error conditions that could cause the creation of the store to fail.
         */
        let container = NSPersistentContainer(name: "MyModel")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in

            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        let description = NSPersistentStoreDescription()
        description.shouldInferMappingModelAutomatically = true
        description.shouldMigrateStoreAutomatically = true
        container.persistentStoreDescriptions.append(description)
        return container
    }()

任何帮助将不胜感激。

【问题讨论】:

  • 要添加新属性,您无需添加新模型版本,只需将属性添加到模型中,Core Data 将为您完成所有工作。
  • @Gigi 这可能是真的,我在添加属性时总是在创建一个新版本。但问题是:如何为已经更新应用的用户安全地解决这个问题?
  • 这可能值得检查,如果我自己解决了这个问题,我会发布,但是当我实例化 NSPersistentContainer 时,我总是在调用 container.loadPersistentStores(:) 之前先 .append(description)
  • @andrewbuilder 这可能是有道理的,在我在谷歌中找到的每个示例中,描述都是在加载之前设置的,如您所提到的。唯一有趣的问题是:迁移到现在是如何进行的?
  • 这是一个有趣的问题。同样,我对此不确定——有人比我更熟悉 Core Data 的详细操作——我猜containerlazy 实例化和description 应用后仍保留在内存中,尽管是在加载商店后发布,因此对persistentContainer 的任何后续调用都可能触发迁移。我很感兴趣,会做更多的研究——如果我找到任何线索,我会告诉你的。

标签: ios swift core-data migration


【解决方案1】:

如果你想编辑描述,你需要在加载商店之前这样做(我不知道添加新描述会做什么):

        container.persistentStoreDescriptions.forEach { storeDesc in
            storeDesc.shouldMigrateStoreAutomatically = true
            storeDesc.shouldInferMappingModelAutomatically = true
        }

        container.loadPersistentStores { [unowned self] (storeDesc, error) in
            if let error = error {
                // handle your error, do not fatalError! even a message that something is wrong can be helpful
                return
            }

            // do any additional work on your view context, etc.
        }

如果您的问题是可重现的,您应该查看返回的错误并查找名为 ZNEWCOLUMN 的内容(虽然这听起来像是一个临时默认名称?)不过,此命名法是 SQL 数据库中的原始列名称,所以很可能迁移者正在尝试添加这个新列并且失败了。

尝试在您的方案的Arguments 中打开 SQL 调试:

-com.apple.CoreData.SQLDebug 1

尝试登录原始 SQL 数据库(如果您在模拟器上,上面将为您提供原始路径)。尝试在以前的操作系统上回滚到以前的数据模型,然后升级到 13。

听起来你在某处有一些重复的列,所以这些只是找出它在哪里的一些想法。

【讨论】:

    【解决方案2】:

    同样的事情发生在我身上,iOS 12 上的轻量级迁移在真实设备和模拟器上是正确的,但在 iOS 13 上失败并显示下一个日志结果:

    SQLite 错误代码:1,'重复的列名:ZNAME_OF_THE_COLUMN .... 错误域 = NSCocoaErrorDomain Code = 134110 "持久存储迁移时出错。"

    我像@iOS Dev post一样加载数据。 我在迁移之前和之后检查了模拟器路径中的 xxxx.sqlite 数据库文件,并且没有具有这些新相同名称的列。 要知道 emulator 中 *.sqlite 的路径,您必须放置一个断点,当它停止时放入控制台 po NSHomeDirectory()。 然后转到 Finder 窗口,点击键 Control + Command + G 并粘贴路线。你可以(例如)使用 DB Browser for SQLite 程序来处理它,它是免费的。

    经过长时间的搜索,我看到了一些人发生了什么,但我没有看到任何解决方案。

    我的是:

    1. 选择实际的 *.xcdatamodel。
    2. 选择编辑器 > 添加模型版本。
    3. 提供基于之前模型的版本名称(如 XxxxxxV2.xcdatamodel)。
    4. 点击这个新版本模型NewV2.xcdatamodel。
    5. 在 IDE 右侧的“属性”中选择此新版本作为当前
    6. 在 DDBB 做出改变。
    7. 运行应用程序即可正常工作。

    我做了覆盖应用程序的测试(使用新值),结果很好。

    我希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2017-09-07
      • 2012-12-14
      • 2014-05-17
      • 1970-01-01
      • 2013-09-23
      • 1970-01-01
      • 2014-05-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多