将Core Data数据库从一个应用程序迁移到另一个应用程序 [英] Migrate Core Data database from one app to another
问题描述
我有一个Core Data数据库,我希望预先填充该数据库,而不必在首次启动时加载所有数据.我正在尝试通过创建另一个应用程序来完成此任务,该应用程序负责加载并将SQL数据库从该应用程序复制到新应用程序.最初,我试图从第二个应用程序中简单地复制 .sqlite
文件,然后将文件复制到第一个应用程序中,如下所示:
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
}()
但是,这给了我一条错误消息,提示无法打开数据库文件".经过研究,我发现了这篇文章: https://developer.apple.com/library/content/qa/qa1809/_index.html
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)")
}
但是,当我执行此操作时,与尝试将复制的DB加载到第一个应用程序时,在导出时会得到与完全相同的错误:无法打开数据库文件".关于我做错了什么或如何使用iOS 10/11和Swift 3/4执行数据库迁移的任何提示?
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?
一些其他有用的信息:
- 两个应用程序在项目创建时都具有Xcode的使用核心数据"选项中的标准CoreData代码
- 从第二个应用程序复制第一个应用程序中的CoreData模型(
.xcdatamodeld
文件),以确保没有不一致之处 - 我能够从第二个应用程序的数据库中添加和获取数据而没有任何问题
- 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
推荐答案
最后,我设法找到了可行的解决方案.我仍然没有弄清楚如何成功导出数据库,但是由于我仅对每个应用程序更新执行一次迁移(或不那么频繁),因此我可以手动复制数据并通过在之前进行简单的测试来验证数据库是否未损坏.提交到App Store.
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
}()
我本质上更改的两件事是确保 NSPersistantStoreDescription
直接指向SQL文件(而不是上面的目录),并且我复制了所有三个文件().sqlite
, .sqlite-shm
和 .sqlite-wal
)添加到documents文件夹.
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.
这篇关于将Core Data数据库从一个应用程序迁移到另一个应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!