2016-10-02 1 views
4

Wie kann ich eine benutzerdefinierte store.sqlite-URL für NSPersistentContainer festlegen?So legen Sie eine benutzerdefinierte Speicher-URL für NSPersistentContainer fest

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() 
} 

}

Gibt es eine nette Art und Weise:

Ich habe eine hässliche Art und Weise, Subklassen NSPersistentContainer gefunden?

Hintergrund: Ich muss in einem freigegebenen App Groups-Verzeichnis speichern.

Antwort

8

Sie tun dies mit der NSPersistentStoreDescription Klasse. Es verfügt über einen Initialisierer, mit dem Sie eine Datei-URL angeben können, auf die sich die persistente Speicherdatei beziehen soll.

let description = NSPersistentStoreDescription(url: myURL) 

Dann verwenden NSPersistentContainer ‚s persistentStoreDescriptions Attribut ihm zu sagen, diesen benutzerdefinierten Speicherort zu verwenden.

container.persistentStoreDescriptions = [description] 

Hinweis: myURL muss die komplette /path/to/model.sqlite, auch zur Verfügung stellen, wenn sie noch nicht existiert. Es wird nicht funktionieren, nur das übergeordnete Verzeichnis zu setzen.

+0

Dies scheint nur zu funktionieren, wenn die store.sqlite bereits existiert, nicht während der Initialisierung des CoreData Stacks. – shallowThought

+0

Nein, es funktioniert gut, wenn die Datei nicht existiert. Das Verzeichnis, in das die Datei verschoben werden soll, muss jedoch vorhanden sein, und Ihre App-Gruppe muss ordnungsgemäß eingerichtet sein. Die Store-Datei muss jedoch nicht bereits vorhanden sein. –

+0

Seltsam. Es stürzt hier mit dem Fehler "Datei nicht gefunden" ab. Funktioniert gut, wenn die Datei bereits existiert. – shallowThought

4

Erweiterung auf Toms Antwort, wenn Sie NSPersistentStoreDescription für jeden Zweck verwenden, müssen Sie mit NSPersistentStoreDescription(url:) weil in meiner Erfahrung init, wenn Sie den Grund initializer verwenden NSPersistentStoreDescription() und loadPersistentStores() auf der Grundlage dieser Beschreibung wird die bestehenden persistenten Speicher überschreiben und all seine Daten beim nächsten Build und Lauf. Hier ist der Code verwende ich für die Einstellung der URL und Beschreibung:

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

ich herausfinden, dass die Lage von db erstellt von PersistentContainer unterscheidet sich von db von UIManagedDocument erstellt. Hier ist eine Momentaufnahme der db Lage von UIManagedDocument:

enter image description here

und die folgenden Codes werden verwendet, um die DB zu erstellen:

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) 
} 

Es sieht aus wie, dass die db bezeichnet durch PersistentContainer ist eigentlich die Datei weiter unten unter dem Ordner "StoreContent" als "persistentStore"

Dies kann erklären, warum die db "defaultDatabase" in meinem Fall nicht von PersistentContainer erstellt werden kann, wenn Sie möchten um die benutzerdefinierte db-Datei anzugeben oder einen Absturz zu verursachen, da der Ordner bereits existiert. Ich überprüfte diese weiter durch einen Dateinamen „MyDb.sqlite“ wie folgt angehängt:

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() { ... } 

Hier ist die neue MyDb.sqlite:

enter image description here

Basierend auf der obigen Analyse, wenn Sie Codes wie folgt:

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

Benutzer Gerät kann auf iOS Pre 10.0 und später auf 10+ aktualisiert werden. Für diese Änderung denke ich, dass die URL angepasst werden muss, um entweder einen Absturz zu vermeiden oder eine neue (leere) Datenbank zu erstellen (Datenverlust).

Verwandte Themen