如何设置自定义store.sqlite URL到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()
}
}
有不错的方式吗?
背景:我需要保存到App Groups共享目录。
答案 0 :(得分:17)
您使用NSPersistentStoreDescription
课程执行此操作。它有一个初始化程序,您可以使用它来提供持久存储文件应该去的文件URL。
let description = NSPersistentStoreDescription(url: myURL)
然后,使用NSPersistentContainer
的{{1}}属性告诉它使用此自定义位置。
persistentStoreDescriptions
注意:container.persistentStoreDescriptions = [description]
必须提供完整的myURL
,即使它尚不存在。仅设置父目录不起作用。
答案 1 :(得分:7)
扩展Tom的回答,当您将NSPersistentStoreDescription
用于任何目的时,请务必使用NSPersistentStoreDescription(url:)
初始化,因为根据我的经验,如果您使用基本初始化程序NSPersistentStoreDescription()
并且loadPersistentStores()
基于该描述,它将在您下次构建和运行时覆盖现有的持久存储及其所有数据。这是我用来设置网址和说明的代码:
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)")
}
}
答案 2 :(得分:2)
我发现PersistentContainer
创建的db的位置与UIManagedDocument
创建的db的位置不同。以下是UIManagedDocument
的数据库位置快照:
以下代码用于创建db:
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" as" persistentStore"
这可以解释为什么db" defaultDatabase"在我的情况下,如果您想要指定自定义的db文件,或由于文件夹已经存在而导致崩溃,则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
...
}
用户&#39;设备可能在iOS 10.0之前,之后更新为10+。对于此更改,我认为必须调整url以避免崩溃或创建新的(空)db(丢失数据)。
答案 3 :(得分:0)
这是我用来初始化可以正常工作的预填充sqlite db的代码。假设您将此数据库用作只读数据库,则无需将其复制到设备上的Documents目录中。
substr(x, 3*(y-1)+1, 3*y)
要记住的一些非常重要的步骤/项目: