将Core Data数据库从一个应用程序迁移到另一个应用程序

时间:2017-09-02 12:36:14

标签: ios swift core-data core-data-migration

我有一个Core Data数据库,我希望预先填充,而不必在首次启动时加载所有数据。我试图通过创建第二个应用程序来完成此操作,该应用程序负责加载并将SQL数据库从该应用程序复制到新应用程序。最初我尝试从第二个应用程序中复制.sqlite文件并将文件复制到第一个应用程序中,如下所示:

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "GeoPointDB")

    let seededData: String = "GeoPointDB"
    var persistentStoreDescriptions: NSPersistentStoreDescription

    let storeUrl = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!

    if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
        let seededDataUrl = Bundle.main.url(forResource: seededData, withExtension: "sqlite")
        try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)

    }

    container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeUrl)]
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error {

            fatalError("Unresolved error \(error),")
        }
    })

    return container

}()

但是,这给了我一条错误消息“无法打开数据库文件”。研究了一下我发现这篇文章: https://developer.apple.com/library/content/qa/qa1809/_index.html

因此我回到了第二个应用程序并试图使用以下代码正确导出数据库:

let documents = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!   
                do {
                    try context.persistentStoreCoordinator!.migratePersistentStore(context.persistentStoreCoordinator!.persistentStores.first!, to: documents, options: nil, withType: NSSQLiteStoreType)
                    print("Managed to save database file")
                } catch let error as NSError {
                    print("Failed to save DB: \(error)")
                }

但是当我这样做时,我在导出时得到完全相同的错误<尝试将复制的数据库加载到第一个应用程序:“无法打开数据库文件”。关于我做错了什么或如何使用iOS 10/11和Swift 3/4执行数据库迁移的任何提示?

可能有用的一些其他信息:

  • 两个应用程序都具有Xcode在项目创建时使用“使用核心数据”选项的标准CoreData代码
  • 第一个应用中的CoreData模型(.xcdatamodeld文件)从第二个应用复制,以确保没有不一致
  • 我可以在没有任何问题的情况下从第二个应用程序的数据库中添加和获取数据

1 个答案:

答案 0 :(得分:1)

最后,我设法找到了一个可行的解决方案。我还没有想出如何成功导出数据库,但由于我只会为每次应用程序更新执行此迁移(或不太频繁),我可以手动复制数据并通过以前简单测试来验证数据库是否已损坏提交到App Store。

关于导入数据库的代码,这就是我最终使用的内容:

lazy var persistentContainer: NSPersistentContainer = {
        let databaseName = "GeoPointDB"

        let container = NSPersistentContainer(name: databaseName)

        var persistentStoreDescriptions: NSPersistentStoreDescription

        let storeUrl = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!.appendingPathComponent(databaseName + ".sqlite")
        let storeUrlFolder = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!

        if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
            let seededDataUrl = Bundle.main.url(forResource: databaseName, withExtension: "sqlite")
            let seededDataUrl2 = Bundle.main.url(forResource: databaseName, withExtension: "sqlite-shm")
            let seededDataUrl3 = Bundle.main.url(forResource: databaseName, withExtension: "sqlite-wal")

            try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)
            try! FileManager.default.copyItem(at: seededDataUrl2!, to: storeUrlFolder.appendingPathComponent(databaseName + ".sqlite-shm"))
            try! FileManager.default.copyItem(at: seededDataUrl3!, to: storeUrlFolder.appendingPathComponent(databaseName + ".sqlite-wal"))

        }

        container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeUrl)]
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error {

                fatalError("Unresolved error \(error),")
            }
        })

        return container
    }()

我实质上改变的两件事是确保NSPersistantStoreDescription直接指向SQL文件(而不是上面的目录)并且我复制了所有三个文件(.sqlite,{ {1}}和.sqlite-shm)到文档文件夹。