2016-12-01 1 views
2

Bevor ich meine Apps auf Swift 3 und iOS 10 aktualisierte, hatte ich keine Probleme mit CoreData als Datenspeicher für einfache Objekte. Leichte Migrationen waren einfach, Speichern und Abrufen war einfach, ect. Aber seit dem letzten Upgrade habe ich nur Probleme mit CoreData gehabt.Swift 3/iOS 10, korrekte Kerndatenverwendung

Meine Frage ist in zwei Teile. Erstens: Kennt jemand gute Ressourcen, um zu lernen, wie CoreData hinter den Kulissen funktioniert, damit ich es besser debuggen kann? Apples Dokumente sind extrem einschränkend und alle Artikel, die ich lese, verhalten sich wie die neuen CoreData so einfach. Ich habe gute Erfahrungen mit relationalen Datenbanken, daher fügt CoreData eine unbequeme Abstraktionsebene für mich hinzu.

Zweitens, was ist falsch mit dem folgenden Code? Leichte Migrationen funktionieren nicht wie vor iOS 10 und verwenden diesen Code. Objekte werden in CoreData gespeichert (ich kann nach dem Speichern mit ihnen in der App interagieren), verschwinden aber nach dem Neustart der App.

lazy var persistentContainer: NSPersistentContainer = { 

    let description = NSPersistentStoreDescription() 

    description.shouldInferMappingModelAutomatically = true 
    description.shouldMigrateStoreAutomatically = true 

    let container = NSPersistentContainer(name: "MY_APP") 
    container.persistentStoreDescriptions = [description] 
    let description = NSPersistentStoreDescription() 

    description.shouldInferMappingModelAutomatically = true 
    description.shouldMigrateStoreAutomatically = true 

    container.persistentStoreDescriptions = [description] 
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in 
     if let error = error as NSError? { 
      fatalError("Unresolved error \(error), \(error.userInfo)") 
     } 
    }) 
    return container 
}() 

// MARK: - Core Data Saving support 

func saveContext() { 
    let context = persistentContainer.viewContext 
    if context.hasChanges { 
     do { 
      try context.save() 
     } catch { 
      let nserror = error as NSError 
      fatalError("Unresolved error \(nserror), \(nserror.userInfo)") 
     } 
    } 
} 

Ich verwende eine separate Datei zu abstrahieren die Speicherung meiner Objekte:

class Repository 
{ 


func getContext() -> NSManagedObjectContext 
{ 
    let appDelegate = UIApplication.shared.delegate as! AppDelegate 
    return appDelegate.persistentContainer.viewContext 
} 


func delete<T>(_ a: some T) 
{ 

    getContext().delete(a as! NSManagedObject) 

} 


// ----------- Password Repo ---------- 


func savePassword(name: String, hint: String, un: String) { 
    let context = getContext() 

    //retrieve the entity that we just created 
    let entity = NSEntityDescription.entity(forEntityName: "Password", in: context) 

    let transc = NSManagedObject(entity: entity!, insertInto: context) 

    //set the entity values 
    transc.setValue(name, forKey: "name") 
    transc.setValue(hint, forKey: "thing") 
    transc.setValue(un, forKey: "newThing") 


    //save the object 
    do { 
     try context.save() 
    } catch let error as NSError { 
     print("Could not save \(error), \(error.userInfo)") 
    } catch { 

    } 
} 


func updatePassword(pas: Password) -> Password 
{ 
    let context = getContext() 
    //  sec.is_new = false 

    // TODO, add updates 

    // Try updating the model in the DB 
    do { 
     try context.save() 
    } catch { 
     print(error) 

    } 

    return pas 
} 


func fetchPasswords() -> [Password] 
{ 

    let context = getContext() 
    //create a fetch request, telling it about the entity 
    let fetchRequest: NSFetchRequest<Password> = Password.fetchRequest() as! NSFetchRequest<Password> 
    let sortDescriptor = NSSortDescriptor(key: "name", ascending: true) 
    fetchRequest.sortDescriptors = [sortDescriptor] 

    do { 
     //go get the results 
     let searchResults = try getContext().fetch(fetchRequest) 
     return searchResults 

    } catch { 
     print("Error with request: \(error)") 
    } 

    return [] 
} 




// ----------- End Password Repo ---------- 





// ----------- Hints Repo ---------- 

func saveHint (name: String, hint: String) { 
    let context = getContext() 

    //retrieve the entity that we just created 
    let entity = NSEntityDescription.entity(forEntityName: "Hint", in: context) 

    let transc = NSManagedObject(entity: entity!, insertInto: context) 

    //set the entity values 
    transc.setValue(value1, forKey: "some_string") 
    transc.setValue(value2, forKey: "some_thing") 

    //save the object 
    do { 
     try context.save() 
    } catch let error as NSError { 
     print("Could not save \(error), \(error.userInfo)") 
    } catch { 

    } 
} 




func fetchHints() -> [Hint] 
{ 

    let context = getContext() 
    //create a fetch request, telling it about the entity 
    let fetchRequest: NSFetchRequest<Hint> = Hint.fetchRequest() as! NSFetchRequest<Hint> 
    let sortDescriptor = NSSortDescriptor(key: "my_key", ascending: true) 
    fetchRequest.sortDescriptors = [sortDescriptor] 

    do { 
     //go get the results 
     let searchResults = try getContext().fetch(fetchRequest) 
     return searchResults 

    } catch { 
     print("Error with request: \(error)") 
    } 

    return [] 
} 

} 

Dann rufe ich diese Repository-Klasse wie folgt:

Repository().savePassword(name: nameText.text!, hint: hintSoFarLabel.text!, un: "Hey") 

Die Repository-Klasse arbeitet , bis ich die App neu starte ...

Ich versuche auch, auf eine neue Version meines Core Da zu migrieren ta Model, das einfach ein nicht optionales String-Attribut (mit Standardwert) hinzufügt, was eine einfache Lightweight-Migration in iOS 9/Swift 2 wäre. Was vermisse ich bei schnellen 3 leichten Migrationen?

Ich habe keinen Zweifel, dass das Problem ist, dass ich CoreData in iOS 10 nicht gut genug verstehe. Ich bin seit einiger Zeit Softwareentwickler, aber ich arbeite erst seit einigen Monaten mit iOS und Swift, also sei bitte sanft. Und danke im Voraus!

+0

Wenn es die Dinge einfacher macht, ist 'NSPersistentContainer' kein Swift-3-Ding, noch ist es erforderlich. Sie können weiterhin die gleichen Klassen wie in früheren Versionen von iOS verwenden. Sie arbeiten immer noch und sind nicht veraltet. Auch verschwindene Objekte würden nicht mit der Migration zusammenhängen. Wenn die Migration eines vorhandenen persistenten Speichers fehlschlägt, stürzt die App beim Start ab. –

+0

@TomHarrington. Danke, das ist ein guter Vorschlag, und ich werde es ausprobieren. Diese spezielle App begann jedoch mit Xcode 8, Swift 3 und einem iOS 10-Ziel. Ich denke, ich sollte bei diesen Paradigmen bleiben. Ich würde gerne herausfinden, wie man mit einer solchen App eine einfache, leichtgewichtige Migration durchführt. Ich habe vorher eine andere App mit iOS 9 geschrieben, also kenne ich iOS9-Migrationen im Vergleich zu iOS10. – Griffin

+0

Ich arbeite an einer einfachen App und neuen Coredata (swift3), ich merke jederzeit, dass ich ShoulderInferMapping ... und ShoulderMigrateStoreAu ... auf true zu Beschreibung setze und sie auf container.persistenStoreDescriptions setze, wie Griffin oben erwähnte, meine Daten nicht bleib bestehen. Aber in dem Moment, in dem ich diese Zeilen kommentiere (setze die beiden Eigenschaften auf "True"), kamen alle meine Daten zurück (bestehen). Irgendeine Idee ? – Ohmy

Antwort

1

Nun, ich fühle mich wie ein Idiot. Ich habe eine nicht optionale Zeichenfolge hinzugefügt und keinen Standardwert angegeben. Ich gab immer Standardwerte für Nicht-String-Typen, aber die Art und Weise, wie Xcode eingerichtet wurde, ließ es so erscheinen, als würde es Strings den Standardwert "" geben, wenn kein anderer angegeben wurde.

Das Hinzufügen eines Standardwerts zum neuen Attribut ermöglichte die Migration in Swift3/iOS10. Noob Fehler, aber vielleicht wird es jemanden hier in der Zukunft helfen.

Verwandte Themen