Migrate Core Data database from one app to another

狂风中的少年 提交于 2021-02-04 21:28:08

问题


I have a Core Data database that I wish to pre-populate without having to load all the data on first launch. I'm trying to do this by creating a second app that takes care of the loading and copy the SQL database from that app to the new one. Initially I tried to simply copy the .sqlite file from the second app and copy the files into the first app like this:

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

}()

However, this gave me an error message saying "unable to open database file". Researching a bit I found this article: https://developer.apple.com/library/content/qa/qa1809/_index.html

I therefore went back to the second app and tried to export the database properly by using this code:

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)")
                }

But when I do this I get the exact same error on export as when trying to load the copied DB to the first app: "unable to open database file". Any tips on what I am doing wrong or how to perform the database migration using iOS 10/11 and Swift 3/4?

Some additional information that might be useful:

  • Both apps have the standard CoreData code from Xcode's "Use Core Data" option on project creation
  • The CoreData model (.xcdatamodeld file) in the first app is copied from the second app to ensure that there are no inconsistencies
  • I am able to add and fetch data from the database of the second application without any issues

回答1:


In the end I managed to find a workable solution. I have still not figured out how to successfully export the database, but since I will only perform this migration once for every app update (or less frequent) I can manually copy the data and verify that the database is not corrupt by simply testing it before submitting to the App Store.

Regarding the code for the import of the database, this is what I ended up using:

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
    }()

The two things I essentially changed was to make sure that the NSPersistantStoreDescription was pointing directly at the SQL file (rather than it's directory as above) and that I copied all three files (.sqlite, .sqlite-shm and .sqlite-wal) to the documents folder.



来源:https://stackoverflow.com/questions/46013862/migrate-core-data-database-from-one-app-to-another

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!