从零开始建 CoreData 数据的话,应该是常规操作了,但是如何导入已经存在的 sqlite 文件供 CoreData 使用呢?
昨天弄了半天,遇到第一个 not found entity
问题,用 momd文件解编译回xcode可识别文件 导入原始的 entity 结构解决。
完成后今天发现一个 mbp 可以正常读取数据了,但是回家 imac 上不能读取数据,依然出现 query entity 时候没有记录的情况。
基本上就是这两个主要的问题,谷歌了这样解决的,请接着往下看。2021-03-25
已更新,请先看更新部分
步骤
看看这个小哥的详细步骤。
Step 1
找到你要导入的 sqlite 文件,可能有三个文件 sqlite,sqlite-shm,sqlite-wal,导入一个 sqlite 也行的。
Populate your Core Data in another app and get files’ path using this code:
let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
print(documentsDirectory)
Step 2
导入文件
Drag your 3 files with .sqlite extension into your xCode project. (Be sure to select Add to targets option).
Step 3
添加这个方法,确保只设置一次。
Create function to check app’s first run in AppDelegate.swift
func isFirstLaunch() -> Bool {
let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag"
let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag)
if (isFirstLaunch) {
UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag)
UserDefaults.standard.synchronize()
}
return isFirstLaunch
}
Step 4
添加这个方法,这个地址是 sqlite 文件即将保存的位置,注意 .applicationSupportDirectory ??
Copy this function in AppDelegate.swift to get url where sqlite database should be moved:
func getDocumentsDirectory()-> URL {
let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
Step 5
执行替换
Replace declaration of persistentContainer with this one:
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "ProjectName")
let storeUrl = self.getDocumentsDirectory().appendingPathComponent("FileName.sqlite")
if isFirstLaunch() {
let seededDataUrl = Bundle.main.url(forResource: "FileName", withExtension: "sqlite")
try! container.persistentStoreCoordinator.replacePersistentStore(at: storeUrl, destinationOptions: nil, withPersistentStoreFrom: seededDataUrl!, sourceOptions: nil, ofType: NSSQLiteStoreType)
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
注意 isFirstLaunch 这个判断句中的细节,之前我用的如下这个时好时坏??包括 FileManager 的 .applicationSupportDirectory 还是 .documentDirectory
if !FileManager.default.fileExists(atPath: (storeUrl.path)) { |
更新
最新教程按照这个来Preload Sqlite data to Core Data,其中把已有的 .sqlite
copy 到相应路径时一定要注意获得路径的方法
就是不要自己拼接 Application Support 的路径 self.getDocumentsDirectory().appendingPathComponent("\(appName).sqlite")
而是用 NSPersistentContainer 的方法来获得 URL(fileURLWithPath: NSPersistentContainer.defaultDirectoryURL().relativePath + "/\(appName).sqlite")
自己拼接的路径会报错。
后一种方法可能会让 core data 去自动生成相关目录。
问题
主要问题
Application Support/xxx.sqlite: No such file or directory
把已有的 .sqlite
copy 到相应路径时一定要注意获得路径的方法
就是不要自己拼接 Application Support 的路径 self.getDocumentsDirectory().appendingPathComponent("\(appName).sqlite")
而是用 NSPersistentContainer 的方法来获得 URL(fileURLWithPath: NSPersistentContainer.defaultDirectoryURL().relativePath + "/\(appName).sqlite")
自己拼接的路径会报错。
找不到对应的 entity
一般就是 xcdatamodeld 里的 entity 字段定义的有出入,大小写敏感的应该??
container.loadPersistentStores 成功后查找数据为0,但是有数据
搜索 pre-filled sqlite
找到 Any way to pre populate core data?,应该是没有正确设置 CoreData 中的 sqlite 文件导致的。
参考
Any way to pre populate core data?
Core Data: preloading an existing SQLite database
Preload Sqlite data to Core Data