如何使用引用了使用 "external storage" 保存的图像的 SQLite 文件预加载核心数据?
How to pre-load Core Data with a SQLite file that have references to images that were saved using "external storage"?
我的目标是在应用程序首次启动时预加载核心数据。到目前为止,我 运行 模拟并用数据填充了 Core Data。 (我勾选了“允许外部存储”)。
我进入 application_support 并复制了:MyApp.sqlite-wal、MyApp.sqlite-shm、.MyApp_SUPPORT/_EXTERNAL_DATA/ 和 MyApp.sqlite.
然后我在我的应用程序包中添加了 MyApp.sqlite 文件,并在我的应用程序委托中添加了这段代码:
lazy var persistentContainer: NSPersistentContainer = {
let modelName = "MyApp"
var container: NSPersistentContainer!
container = NSPersistentContainer(name: modelName)
// Preloading
let appName: String = "MyApp"
var persistentStoreDescriptions: NSPersistentStoreDescription
let storeUrl = self.getDocumentsDirectory().appendingPathComponent("MyApp.sqlite")
if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
let seededDataUrl = Bundle.main.url(forResource: appName, withExtension: "sqlite")
try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)
}
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
description.url = storeUrl
container.persistentStoreDescriptions = [description]
//End Preloading
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
它有效,但它似乎找不到保存在外部存储器中的图像。它们作为参考出现在 .MyApp_SUPPORT/_EXTERNAL_DATA 中。
我应该在哪里添加参考文献?
加载一切是我的目标。
如果你有一个名为 MyApp.sqlite
的文件,在某个目录(这里是应用程序包)中有外部二进制存储,Core Data 会将这些文件放在一个名为 .MyApp_SUPPORT/_EXTERNAL_DATA/
的子目录中。您需要递归复制该目录及其子目录中的所有内容。
不过,使用该路径不是一个好主意,因为它没有记录并且可能会在没有警告的情况下更改。此外,这将错过 MyApp.sqlite-wal
和 MyApp.sqlite-shm
,如果它们存在的话。
更好的办法是将种子库放在自己的自定义目录中,然后从 那个 目录复制所有内容。您将拥有一个名为 MyAppSeedData
的目录,而不是只有 MyApp.sqlite
,其中将包含 MyApp.sqlite
。它还将包含 Core Data 所需的所有其他内容,如外部二进制文件。使用相同的 FileManager
函数复制 MyAppSeedData
目录(因为它会递归复制每个文件),你应该没问题。
复制文件夹的代码如下所示:
if let sourceDirURL = Bundle.main.url(forResource: "Source Folder", withExtension: nil) {
let destinationDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("TestFolder")
if !FileManager.default.fileExists(atPath: destinationDirURL.path) {
do {
try FileManager.default.copyItem(at: sourceDirURL, to: destinationDirURL)
} catch {
print("Error copying directory: \(error)")
}
}
}
然后您可以将 SQLite 文件名添加到 destinationDirURL
的末尾并将其用于核心数据。
第 1 步:创建“MyAppSeedData”目录并粘贴 MyApp.sqlite、MyApp_SUPPORT、MyApp.sqilte-smh、MyApp.sqilte-wal 文件。
第 2 步:将 MyAppSeedData 拖到 AppDelegate 下的包中,然后勾选添加目标框。
第 3 步:这些函数必须在 AppDelegate 文件中:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
//If first launch condition == true {
seedData()
//}
return true
}
func seedData() {
let fm = FileManager.default
//Destination URL: Application Folder
let libURL = fm.urls(for: .libraryDirectory, in: .userDomainMask).first!
let destFolder = libURL.appendingPathComponent("Application Support").path
//Or
//let l1 = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last!
//
//Starting URL: MyAppSeedData dir
let folderPath = Bundle.main.resourceURL!.appendingPathComponent("MyAppSeedData").path
let fileManager = FileManager.default
let urls = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask)
if let applicationSupportURL = urls.last {
do{
try fileManager.createDirectory(at: applicationSupportURL, withIntermediateDirectories: true, attributes: nil)
}
catch{
print(error)
}
}
copyFiles(pathFromBundle: folderPath, pathDestDocs: destFolder)
}
func copyFiles(pathFromBundle : String, pathDestDocs: String) {
let fm = FileManager.default
do {
let filelist = try fm.contentsOfDirectory(atPath: pathFromBundle)
let fileDestList = try fm.contentsOfDirectory(atPath: pathDestDocs)
for filename in fileDestList {
try FileManager.default.removeItem(atPath: "\(pathDestDocs)/\(filename)")
}
for filename in filelist {
try? fm.copyItem(atPath: "\(pathFromBundle)/\(filename)", toPath: "\(pathDestDocs)/\(filename)")
}
} catch {
print("Error info: \(error)")
}
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let modelName = "MyApp"
var container: NSPersistentContainer!
container = NSPersistentContainer(name: modelName)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
我的目标是在应用程序首次启动时预加载核心数据。到目前为止,我 运行 模拟并用数据填充了 Core Data。 (我勾选了“允许外部存储”)。
我进入 application_support 并复制了:MyApp.sqlite-wal、MyApp.sqlite-shm、.MyApp_SUPPORT/_EXTERNAL_DATA/ 和 MyApp.sqlite.
然后我在我的应用程序包中添加了 MyApp.sqlite 文件,并在我的应用程序委托中添加了这段代码:
lazy var persistentContainer: NSPersistentContainer = {
let modelName = "MyApp"
var container: NSPersistentContainer!
container = NSPersistentContainer(name: modelName)
// Preloading
let appName: String = "MyApp"
var persistentStoreDescriptions: NSPersistentStoreDescription
let storeUrl = self.getDocumentsDirectory().appendingPathComponent("MyApp.sqlite")
if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
let seededDataUrl = Bundle.main.url(forResource: appName, withExtension: "sqlite")
try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)
}
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
description.url = storeUrl
container.persistentStoreDescriptions = [description]
//End Preloading
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
它有效,但它似乎找不到保存在外部存储器中的图像。它们作为参考出现在 .MyApp_SUPPORT/_EXTERNAL_DATA 中。 我应该在哪里添加参考文献?
加载一切是我的目标。
如果你有一个名为 MyApp.sqlite
的文件,在某个目录(这里是应用程序包)中有外部二进制存储,Core Data 会将这些文件放在一个名为 .MyApp_SUPPORT/_EXTERNAL_DATA/
的子目录中。您需要递归复制该目录及其子目录中的所有内容。
不过,使用该路径不是一个好主意,因为它没有记录并且可能会在没有警告的情况下更改。此外,这将错过 MyApp.sqlite-wal
和 MyApp.sqlite-shm
,如果它们存在的话。
更好的办法是将种子库放在自己的自定义目录中,然后从 那个 目录复制所有内容。您将拥有一个名为 MyAppSeedData
的目录,而不是只有 MyApp.sqlite
,其中将包含 MyApp.sqlite
。它还将包含 Core Data 所需的所有其他内容,如外部二进制文件。使用相同的 FileManager
函数复制 MyAppSeedData
目录(因为它会递归复制每个文件),你应该没问题。
复制文件夹的代码如下所示:
if let sourceDirURL = Bundle.main.url(forResource: "Source Folder", withExtension: nil) {
let destinationDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("TestFolder")
if !FileManager.default.fileExists(atPath: destinationDirURL.path) {
do {
try FileManager.default.copyItem(at: sourceDirURL, to: destinationDirURL)
} catch {
print("Error copying directory: \(error)")
}
}
}
然后您可以将 SQLite 文件名添加到 destinationDirURL
的末尾并将其用于核心数据。
第 1 步:创建“MyAppSeedData”目录并粘贴 MyApp.sqlite、MyApp_SUPPORT、MyApp.sqilte-smh、MyApp.sqilte-wal 文件。
第 2 步:将 MyAppSeedData 拖到 AppDelegate 下的包中,然后勾选添加目标框。
第 3 步:这些函数必须在 AppDelegate 文件中:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
//If first launch condition == true {
seedData()
//}
return true
}
func seedData() {
let fm = FileManager.default
//Destination URL: Application Folder
let libURL = fm.urls(for: .libraryDirectory, in: .userDomainMask).first!
let destFolder = libURL.appendingPathComponent("Application Support").path
//Or
//let l1 = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last!
//
//Starting URL: MyAppSeedData dir
let folderPath = Bundle.main.resourceURL!.appendingPathComponent("MyAppSeedData").path
let fileManager = FileManager.default
let urls = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask)
if let applicationSupportURL = urls.last {
do{
try fileManager.createDirectory(at: applicationSupportURL, withIntermediateDirectories: true, attributes: nil)
}
catch{
print(error)
}
}
copyFiles(pathFromBundle: folderPath, pathDestDocs: destFolder)
}
func copyFiles(pathFromBundle : String, pathDestDocs: String) {
let fm = FileManager.default
do {
let filelist = try fm.contentsOfDirectory(atPath: pathFromBundle)
let fileDestList = try fm.contentsOfDirectory(atPath: pathDestDocs)
for filename in fileDestList {
try FileManager.default.removeItem(atPath: "\(pathDestDocs)/\(filename)")
}
for filename in filelist {
try? fm.copyItem(atPath: "\(pathFromBundle)/\(filename)", toPath: "\(pathDestDocs)/\(filename)")
}
} catch {
print("Error info: \(error)")
}
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let modelName = "MyApp"
var container: NSPersistentContainer!
container = NSPersistentContainer(name: modelName)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()