Перенос базы данных 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
) в папку с документами.