如何为NSPersistentContainer设置自定义商店网址
如何将自定义store.sqlite网址设置为NSPersistentContainer?如何为NSPersistentContainer设置自定义商店网址
我发现了一个丑陋的方式,继承NSPersistentContainer:
final public class PersistentContainer: NSPersistentContainer {
private static var customUrl: URL?
public init(name: String, managedObjectModel model: NSManagedObjectModel, customStoreDirectory baseUrl:URL?) {
super.init(name: name, managedObjectModel: model)
PersistentContainer.customUrl = baseUrl
}
override public class func defaultDirectoryURL() -> URL {
return (customUrl != nil) ? customUrl! : super.defaultDirectoryURL()
}
}
有没有好方法?
背景:我需要保存到应用程序组共享目录。
您可以使用NSPersistentStoreDescription
类来做到这一点。它有一个初始化程序,您可以使用该初始化程序来提供持久存储文件应该放到的文件URL。
let description = NSPersistentStoreDescription(url: myURL)
然后,使用NSPersistentContainer
的persistentStoreDescriptions
属性来告诉它使用这个自定义位置。
container.persistentStoreDescriptions = [description]
注:myURL
必须提供完整的/path/to/model.sqlite
,即使不存在了。它不会仅用于设置父目录。
扩大汤姆的答案,当您使用NSPersistentStoreDescription
用于任何目的,一定要与NSPersistentStoreDescription(url:)
来初始化,因为在我的经验,如果你使用基本的初始化NSPersistentStoreDescription()
和loadPersistentStores()
基于这样的描述,它会覆盖现有的持久性存储和所有它的数据在您下次构建和运行时。下面是我使用的设置URL和说明代码:
let container = NSPersistentContainer(name: "MyApp")
let storeDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
let url = storeDirectory.appendingPathComponent("MyApp.sqlite")
let description = NSPersistentStoreDescription(url: url)
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { (storeDescription, error) in
if let error = error as? NSError {
print("Unresolved error: \(error), \(error.userInfo)")
}
}
我刚刚发现,由PersistentContainer
创建数据库的位置是从数据库通过UIManagedDocument
创建不同的。下面是UIManagedDocument
分贝位置的快照:
和下面的代码用于创建数据库:
let fileURL = db.fileURL // url to ".../Documents/defaultDatabase"
let fileExist = FileManager.default.fileExists(atPath: fileURL.path)
if fileExist {
let state = db.documentState
if state.contains(UIDocumentState.closed) {
db.open()
}
} else {
// Create database
db.save(to: fileURL, for:.forCreating)
}
它看起来像由PersistentContainer
简称分贝实际上是文件在文件夹“StoreContent”下作为“persistentStore”
这可以解释为什么在我的情况下db“defaultDatabase”不能被PersistentContainer
创建,如果你想要指定您的自定义数据库文件,或导致崩溃,因为文件夹已经存在。我进一步证实了这一附加一个文件名“MyDb.sqlite”是这样的:
let url = db.fileURL.appendingPathComponent("MyDb.sqlite")
let storeDesription = NSPersistentStoreDescription(url: url)
container.persistentStoreDescriptions = [storeDesription]
print("store description \(container.persistentStoreDescriptions)"
// store description [<NSPersistentStoreDescription: 0x60000005cc50> (type: SQLite, url: file:///Users/.../Documents/defaultDatabase/MyDb.sqlite)
container.loadPersistentStores() { ... }
这是新MyDb.sqlite:
基于上述分析,如果你有这样的代码:
if #available(iOS 10.0, *) {
// load db by using PersistentContainer
...
} else {
// Fallback on UIManagedDocument method to load db
...
}
用户的设备可能在iOS 10.0之前,并且以后更新到10+。对于这个改变,我认为url必须被调整以避免崩溃或者创建一个新的(空的)db(丢失数据)。
这似乎只适用于,如果store.sqlite已经存在,而不是初始化CoreData堆栈。 – shallowThought
不,它工作正常,如果该文件不存在。但是,您想要文件的目录必须存在,并且您的应用程序组需要正确设置。不过,没有要求存储文件已经存在。 –
奇怪。它与“找不到文件”错误在这里崩溃。如果文件已经存在,可以正常工作。 – shallowThought