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

Posted

技术标签:

【中文标题】将 Core Data 数据库从一个应用程序迁移到另一个应用程序【英文标题】:Migrate Core Data database from one app to another 【发布时间】:2017-09-02 12:36:14 【问题描述】:

我有一个 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】:

最后我设法找到了一个可行的解决方案。我还没有弄清楚如何成功导出数据库,但由于我只会为每次应用程序更新(或更不频繁)执行一次此迁移,我可以手动复制数据并通过简单地测试来验证数据库没有损坏之前提交到 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.sqlite-shm 和 @ 987654325@) 到文档文件夹。

【讨论】:

以上是关于将 Core Data 数据库从一个应用程序迁移到另一个应用程序的主要内容,如果未能解决你的问题,请参考以下文章

将 Core Data 应用程序迁移到 iCloud

如何将一个 Core Data 模型迁移到一个全新的模型?

轻量级迁移后如何从 Core Data 中删除数据

在 Core Data 中使用数据模型迁移时应用程序崩溃

如何从Core Data中的字符串获取Processed字符串

执行 Core Data 迁移时,如何从不同实体的源存储中继承旧值?