2016-10-02 68 views
4

如何將自定義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() 
} 

}

有沒有好方法?

背景:我需要保存到應用程序組共享目錄。

回答

8

您可以使用NSPersistentStoreDescription類來做到這一點。它有一個初始化程序,您可以使用該初始化程序來提供持久存儲文件應該放到的文件URL。

let description = NSPersistentStoreDescription(url: myURL) 

然後,使用NSPersistentContainerpersistentStoreDescriptions屬性來告訴它使用這個自定義位置。

container.persistentStoreDescriptions = [description] 

注:myURL必須提供完整的/path/to/model.sqlite,即使不存在了。它不會僅用於設置父目錄。

+0

這似乎只適用於,如果store.sqlite已經存在,而不是初始化CoreData堆棧。 – shallowThought

+0

不,它工作正常,如果該文件不存在。但是,您想要文件的目錄必須存在,並且您的應用程序組需要正確設置。不過,沒有要求存儲文件已經存在。 –

+0

奇怪。它與「找不到文件」錯誤在這裏崩潰。如果文件已經存在,可以正常工作。 – shallowThought

4

擴大湯姆的答案,當您使用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)") 
    } 
} 
1

我剛剛發現,由PersistentContainer創建數據庫的位置是從數據庫通過UIManagedDocument創建不同的。下面是UIManagedDocument分貝位置的快照:

enter image description here

和下面的代碼用於創建數據庫:

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:

enter image description here

基於上述分析,如果你有這樣的代碼:

if #available(iOS 10.0, *) { 
    // load db by using PersistentContainer 
    ... 
} else { 
    // Fallback on UIManagedDocument method to load db 
    ... 
} 

用戶的設備可能在iOS 10.0之前,並且以後更新到10+。對於這個改變,我認爲url必須被調整以避免崩潰或者創建一個新的(空的)db(丟失數據)。

相關問題