如何使用SQLite文件预加载核心数据,该文件引用了使用"external storage"保存的图像?



我的目标是在第一次应用程序发布时预加载核心数据。到目前为止,我运行了一个模拟,并用数据填充了核心数据。(我已经勾选了"允许外部存储")。

我进入application_support并复制了:MyApp.sqlite-wal、MyApp.sqlite-shm、.MyApp_support/EXTERNAL_DATA/和MyApp.sql ite.

然后,我在我的应用程序捆绑包中添加了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-walMyApp.sqlite-shm(如果它们存在的话)。

一个更好的想法是将种子存储放在自己的自定义目录中,并复制目录中的所有内容。您将有一个名为MyAppSeedData的目录,其中包含MyApp.sqlite,而不是只有MyApp.sqlite。它还将包含核心数据所需的所有其他内容,如外部二进制文件。使用相同的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";dir并将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
}()

相关内容