Перенос базы данных Core Data из одного приложения в другое

У меня есть база данных 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?

Некоторая дополнительная информация, которая может быть полезна:

  • Оба приложения имеют стандартный код CoreData из опции "Использовать основные данные" в Xcode при создании проекта.
  • Модель 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 а также .sqlite-wal) в папку с документами.

Другие вопросы по тегам