Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Core Data

Core Data von Grund auf neu: Migrationen

by
Read Time:14 minsLanguages:
This post is part of a series called Core Data from Scratch.
Core Data from Scratch: More NSFetchedResultsController
Core Data from Scratch: Subclassing NSManagedObject

German (Deutsch) translation by Federicco Ancie (you can also view the original English article)

In den vorherigen Artikeln dieser Reihe sind wir auf ein nerviges Problem gestoßen, das wir angehen müssen. Immer wenn wir das Datenmodell einer Core Data-Anwendung ändern, wird der persistente Speicher nicht mehr mit dem Datenmodell kompatibel. Das Ergebnis ist ein Absturz beim Start, der die Anwendung unbrauchbar macht. Dies ist ein ernstes Problem, wenn dies bei einer Anwendung im App Store auftritt.

Unsere Anwendung stürzt ab, weil wir in der persistentStoreCoordinator-Methode abort aufrufen, wenn das Hinzufügen des persistenten Speichers zum persistenten Speicherkoordinator nicht erfolgreich ist. Die abort- Funktion bewirkt, dass die Anwendung sofort beendet wird.

Es ist jedoch nicht erforderlich, unsere Anwendung zu beenden, geschweige denn sie zum Absturz zu bringen. Wenn Core Data uns mitteilt, dass das Datenmodell und der persistente Speicher nicht kompatibel sind, müssen wir dies beheben.

In diesem Artikel werden zwei Optionen zur Wiederherstellung aus einer solchen Situation erläutert: Migrieren des persistenten Speichers und Erstellen eines neuen persistenten Speichers, der mit dem geänderten Datenmodell kompatibel ist.

1. Das Problem

Lassen Sie mich zunächst das Problem klären, das wir zu lösen versuchen. Laden Sie das Beispielprojekt herunter, das wir im vorherigen Artikel erstellt haben, und führen Sie es im iOS-Simulator aus. Die Anwendung sollte einwandfrei funktionieren.

Öffnen Sie Done.xcdatamodeld und fügen Sie der TSPItem-Entität ein Attribut updateAt vom Typ Date hinzu. Führen Sie die Anwendung noch einmal aus und stellen Sie fest, wie die Anwendung abstürzt, sobald sie gestartet wird. Glücklicherweise gibt uns Core Data einen Hinweis darauf, was schief gelaufen ist. Sehen Sie sich die Ausgabe in der Xcode-Konsole an.

In der letzten Zeile teilt Core Data mit, dass das Datenmodell, mit dem der persistente Speicher geöffnet wurde, nicht mit dem Datenmodell kompatibel ist, mit dem der persistente Speicher erstellt wurde. Warten. Was?

Als wir die Anwendung zum ersten Mal starteten, erstellte Core Data eine SQLite-Datenbank basierend auf dem Datenmodell. Da wir das Datenmodell jedoch geändert haben, indem wir der TSPItem-Entität ein Attribut, updateAt, hinzugefügt haben, versteht Core Data nicht mehr, wie TSPItem-Datensätze in der SQLite-Datenbank gespeichert werden sollen. Mit anderen Worten, das geänderte Datenmodell ist nicht mehr mit dem zuvor erstellten persistenten Speicher kompatibel.

2. Die Lösung

Zum Glück haben einige clevere Ingenieure von Apple eine Lösung entwickelt, um ein Datenmodell sicher zu ändern, ohne auf Inkompatibilitätsprobleme zu stoßen. Um das Problem zu lösen, müssen wir einen Weg finden, um Core Data mitzuteilen, wie sich eine Version des Datenmodells auf eine andere Version bezieht. Die Versionierung des Datenmodells ist Teil der Lösung.

Mit diesen Informationen kann Core Data verstehen, wie der persistente Speicher aktualisiert werden muss, um mit dem geänderten Datenmodell, dh der neuen Version des Datenmodells, kompatibel zu sein. Mit anderen Worten, wir müssen Core Data die erforderlichen Informationen übergeben, um den persistenten Speicher von einer Version des Datenmodells auf eine andere zu migrieren.

3. Migrationen

Es gibt zwei Arten von Migrationen: leichte und schwere Migrationen. Die Wörter leicht und schwer sind ziemlich beschreibend, aber es ist wichtig, dass Sie verstehen, wie Core Data mit jeder Art von Migration umgeht.

Leichte Migrationen

Leichte Migrationen erfordern nur sehr wenig Arbeit von Ihrer Seite, dem Entwickler. Ich empfehle dringend, dass Sie eine leichte Migration einer schweren Migration vorziehen, wann immer Sie können. Die Kosten einer leichten Migration sind wesentlich niedriger als die einer schweren Migration.

Die Kehrseite von leichten Migrationen ist natürlich, dass sie weniger leistungsfähig sind als schwere Migrationen. Die Änderungen, die Sie an einem Datenmodell mit einfachen Migrationen vornehmen können, sind begrenzt. Mit einer einfachen Migration können Sie beispielsweise Attribute und Entitäten hinzufügen oder umbenennen, aber Sie können den Typ eines Attributs oder die Beziehungen zwischen vorhandenen Entitäten nicht ändern.

Leichte Migrationen sind ideal, um das Datenmodell zu erweitern und Attribute und Entitäten hinzuzufügen. Wenn Sie vorhaben, Beziehungen zu ändern oder Attributtypen zu ändern, stehen Sie vor einer wilden Fahrt mit starken Migrationen.

Schwere Migrationen

Schwere Migrationen sind etwas schwieriger. Lassen Sie mich das umformulieren. Starke Migrationen sind ein Schmerz im Nacken und Sie sollten versuchen, sie nach Möglichkeit zu vermeiden. Schwere Migrationen sind mächtig, aber diese Macht hat ihren Preis. Schwere Migrationen erfordern viel Arbeit und Tests, um sicherzustellen, dass die Migration erfolgreich und vor allem ohne Datenverlust abgeschlossen wird.

Wir betreten die Welt der starken Migrationen, wenn wir Änderungen vornehmen, auf die Core Data nicht automatisch schließen kann, indem wir Versionen des Datenmodells vergleichen. Core Data benötigt dann ein Mapping-Modell, um zu verstehen, wie die Versionen des Datenmodells zueinander in Beziehung stehen. Da schwere Migrationen ein komplexes Thema sind, werden wir es in dieser Reihe nicht behandeln.

4. Versionierung

Wenn Sie mit Ruby on Rails gearbeitet haben, sind Migrationen für Sie sehr sinnvoll. Die Idee ist einfach, aber mächtig. Mit Core Data können wir das Datenmodell versionieren und das Datenmodell sicher ändern. Core Data überprüft das versionierte Datenmodell, um zu verstehen, wie sich der persistente Speicher auf das Datenmodell bezieht. Wenn Sie sich das versionierte Datenmodell ansehen, wissen Sie auch, ob der persistente Speicher migriert werden muss, bevor er mit der aktuellen Version des Datenmodells verwendet werden kann.

Versionierung und Migration gehen Hand in Hand. Wenn Sie verstehen möchten, wie Migrationen funktionieren, müssen Sie zunächst verstehen, wie das Core Data-Datenmodell versioniert wird. Lassen Sie uns die Aufgabenanwendung, die wir im vorherigen Artikel erstellt haben, erneut betrachten. Wie bereits erwähnt, führt das Hinzufügen des Attributs updatedAt zur TSPItem-Entität dazu, dass der persistente Speicher nicht mit dem geänderten Datenmodell kompatibel ist. Wir verstehen jetzt die Ursache dafür.

Beginnen wir mit einem sauberen Slate, indem wir Done.xcdatamodeld öffnen und das updateAt-Attribut aus der TSPItem-Entität entfernen. Es ist Zeit, eine neue Version des Datenmodells zu erstellen.

Wählen Sie bei ausgewähltem Datenmodell im Menü Editor die Option Modellversion hinzufügen. Xcode fordert Sie auf, die neue Datenmodellversion und vor allem die Version zu nennen, auf der die neue Version basieren soll. Um sicherzustellen, dass Core Data den persistenten Speicher für uns migrieren kann, ist es wichtig, dass Sie die vorherige Version des Datenmodells auswählen. In diesem Beispiel haben wir nur eine Wahl.

Das Ergebnis dieser Aktion ist, dass wir jetzt drei Datenmodelldateien im Projektnavigator sehen können. Es gibt ein Datenmodell der obersten Ebene mit der Erweiterung .xcdatamodeld und zwei untergeordnete Elemente mit der Erweiterung .xcdatamodel.

Sie können die .xcdatamodeld-Datei als Paket für die Versionen des Datenmodells anzeigen, wobei jede Version durch eine .xcdatamodel-Datei dargestellt wird. Sie können dies überprüfen, indem Sie mit der rechten Maustaste auf die .xcdatamodeld-Datei klicken und Im Finder anzeigen auswählen. Dadurch gelangen Sie zum Datenmodell im Xcode-Projekt. Wenn Sie mit der rechten Maustaste auf diese Datei klicken und Paketinhalt anzeigen auswählen, sollten die beiden Versionen des Datenmodells Done.xcdatamodel und Done 2.xcdatamodel angezeigt werden.

Haben Sie im Projektnavigator bemerkt, dass eine der Versionen ein grünes Häkchen hat? Dieses Häkchen zeigt die aktuelle Modellversion an, in diesem Beispiel Done.xcdatamodel. Mit anderen Worten, obwohl wir eine neue Version des Datenmodells erstellt haben, wird es von unserer Anwendung noch nicht verwendet. Bevor wir dies ändern, müssen wir Core Data mitteilen, was mit dem versionierten Datenmodell geschehen soll.

Wir müssen Core Data mitteilen, wie der persistente Speicher für das Datenmodell migriert werden soll. Wir tun dies in der persistentStoreCoordinator-Methode in TSPAppDelegate.m. In der persistentStoreCoordinator-Methode erstellen wir den persistenten Speicherkoordinator und fügen ihm einen persistenten Speicher hinzu, indem wir addPersistentStoreWithType:configuration:URL:options: error: aufrufen. Das ist nichts Neues.

Der vierte Parameter dieser Methode, ein Wörterbuch mit Optionen, ist derzeit nil. Dieses Optionswörterbuch enthält Anweisungen für Core Data. Es gibt uns die Möglichkeit, dem Koordinator für persistente Speicher mitzuteilen, wie der persistente Speicher, den wir hinzufügen, migriert werden soll.

Schauen Sie sich die aktualisierte Implementierung von persistentStoreCoordinator an, in der wir ein Optionswörterbuch mit zwei Schlüssel-Wert-Paaren übergeben.

Der erste Schlüssel, NSMigratePersistentStoresAutomaticallyOption, teilt Core Data mit, dass wir versuchen möchten, den persistenten Speicher für uns zu migrieren. Der zweite Schlüssel, NSInferMappingModelAutomaticallyOption, weist Core Data an, das Zuordnungsmodell für die Migration abzuleiten. Genau das wollen wir. Es sollte ohne Probleme funktionieren, solange es sich um eine einfache Migration handelt.

Mit dieser Änderung sind wir bereit, das Datenmodell auf die neue Version zu migrieren, die wir vor wenigen Augenblicken erstellt haben. Wählen Sie zunächst die neue Version Done 2.xcdatamodel aus und fügen Sie der TSPItem-Entität ein neues Attribut updateAt vom Typ Date hinzu.

Wir müssen auch die neue Datenmodellversion als die von Core Data zu verwendende Version markieren. Wählen Sie im Projektnavigator Done.xcdatamodeld aus und öffnen Sie den Dateiinspektor auf der rechten Seite. Setzen Sie im Abschnitt Modellversion Aktuell auf Done 2.

Im Projektnavigator sollte Done 2.xcdatamodel jetzt ein grünes Häkchen anstelle von Done.xcdatamodel haben.

Mit dieser Änderung können Sie die Anwendung sicher erstellen und ausführen. Wenn Sie die obigen Schritte ausgeführt haben, sollte Core Data den persistenten Speicher automatisch für Sie migrieren, indem Sie das Zuordnungsmodell basierend auf dem versionierten Datenmodell ableiten.

Beachten Sie, dass Sie einige Vorsichtsmaßnahmen beachten sollten. Wenn Sie auf einen Absturz stoßen, haben Sie etwas falsch gemacht. Wenn Sie beispielsweise die Datenmodellversion auf Done 2.xcdatamodel festgelegt, die Anwendung ausgeführt und dann Änderungen an Done 2.xcdatamodel vorgenommen haben, kommt es unweigerlich zu einem Absturz, da der persistente Speicher nicht mit dem kompatibel ist Datenmodell. Leichte Migrationen sind relativ leistungsfähig und einfach zu implementieren. Dies bedeutet jedoch nicht, dass Sie das Datenmodell jederzeit ändern können.

Die Datenschicht eines Softwareprojekts erfordert Sorgfalt, Aufmerksamkeit und Vorbereitung. Migrationen sind großartig, sollten aber sparsam eingesetzt werden. Abstürze sind während der Entwicklung kein Problem, aber in der Produktion katastrophal. Im nächsten Abschnitt sehen wir uns genauer an, was dies bedeutet und wie Abstürze aufgrund einer problematischen Migration verhindert werden können.

5. Abstürze vermeiden

Ich bin noch nie in eine Situation geraten, in der ein abort in der Produktion gerechtfertigt war, und es schmerzt mich, wenn ich ein Projekt durchsuche, in dem die Standardimplementierung von Apple zum Einrichten des Core Data Stacks verwendet wird, in dem ein abort aufgerufen wird, wenn das Hinzufügen eines dauerhaften Speichers nicht erfolgreich ist.

Das Vermeiden von abort ist nicht so schwierig, erfordert jedoch einige Codezeilen und informiert den Benutzer darüber, was schief gelaufen ist, falls etwas schief geht. Entwickler sind nur Menschen und wir alle machen Fehler.

Schritt 1: abort loswerden

Öffnen Sie zunächst TSPAppDelegate.m und entfernen Sie die Zeile, in der wir abort aufrufen. Das ist der erste Schritt zu einem zufriedenen Benutzer.

Schritt 2: Verschieben des inkompatiblen Speichers

Wenn Core Data feststellt, dass der persistente Speicher nicht mit dem Datenmodell kompatibel ist, verschieben wir den inkompatiblen Speicher zunächst an einen sicheren Ort. Wir tun dies, um sicherzustellen, dass die Daten des Benutzers nicht verloren gehen. Selbst wenn das Datenmodell nicht mit dem persistenten Speicher kompatibel ist, können Sie möglicherweise Daten daraus wiederherstellen. Sehen Sie sich die aktualisierte Implementierung der persistentStoreCoordinator-Methode in TSPAppDelegate.m an.

Beachten Sie, dass ich den Wert von storeURL geändert habe, den Speicherort des persistenten Speichers. Es zeigt auf ein Verzeichnis im documents verzeichnis in der Sandbox der Anwendung. Die Implementierung von applicationStoresDirectory, einer Hilfsmethode, ist unkompliziert, wie Sie unten sehen können.

Wenn der persistente Speicherkoordinator den vorhandenen persistenten Speicher in storeURL nicht hinzufügen kann, verschieben wir den persistenten Speicher in ein separates Verzeichnis. Beachten Sie, dass wir zwei weitere Hilfsmethoden verwenden, applicationIncompatibleStoresDirectory und nameForIncompatibleStore. Die Implementierung von applicationIncompatibleStoresDirectory ist ziemlich einfach, wie Sie unten sehen können.

In nameForIncompatibleStore generieren wir einen Namen für den inkompatiblen Speicher basierend auf dem aktuellen Datum und der aktuellen Uhrzeit, um Namenskollisionen zu vermeiden.

Schritt 3: Erstellen eines neuen persistenten Speichers

Es ist Zeit, einen neuen persistenten Speicher zu erstellen, um die Einrichtung des Core Data-Stacks abzuschließen. Die nächsten paar Zeilen sollten inzwischen sehr vertraut aussehen.

Wenn Core Data keinen neuen persistenten Speicher erstellen kann, gibt es schwerwiegendere Probleme, die nicht damit zusammenhängen, dass das Datenmodell nicht mit dem persistenten Speicher kompatibel ist. Wenn Sie auf dieses Problem stoßen, überprüfen Sie den Wert von storeURL.

Schritt 4: Benachrichtigen Sie den Benutzer

Dieser Schritt ist wahrscheinlich der wichtigste für die Erstellung einer benutzerfreundlichen Anwendung. Der Verlust der Benutzerdaten ist eine Sache, aber vorzutäuschen, dass nichts passiert ist, ist nicht schön. Wie würden Sie sich fühlen, wenn eine Fluggesellschaft Ihr Gepäck verlieren würde und so tun würde, als wäre nichts passiert?

Wir zeigen dem Benutzer eine Warnansicht, aber es ist eine gute Idee, ein paar Schritte weiter zu gehen. Sie können sie beispielsweise auffordern, sich an den Support zu wenden, und Sie können sogar eine Funktion implementieren, mit der sie Ihnen den beschädigten Speicher senden können. Letzteres ist sehr nützlich zum Debuggen des Problems.

Schritt 5: Testen

Persistente Daten sind ein wichtiger Aspekt der meisten Anwendungen. Es ist daher wichtig, ordnungsgemäß zu testen, was wir in diesem Artikel implementiert haben. Führen Sie zum Testen unserer Wiederherstellungsstrategie die Anwendung im iOS-Simulator aus und überprüfen Sie, ob der persistente Speicher erfolgreich im Verzeichnis Application Support im Unterverzeichnis Stores erstellt wurde.

Fügen Sie der TSPItem-Entität in Done 2.xcdatamodel ein neues Attribut hinzu und führen Sie die Anwendung noch einmal aus. Da der vorhandene persistente Speicher jetzt nicht mit dem Datenmodell kompatibel ist, wird der inkompatible persistente Speicher in das Unterverzeichnis Inkompatibel verschoben und ein neuer persistenter Speicher erstellt. Sie sollten auch eine Warnansicht sehen, die den Benutzer über das Problem informiert.

Abschluss

Migrationen sind ein wichtiges Thema, wenn Sie Core Data umfassend nutzen möchten. Mit Migrationen können Sie das Datenmodell Ihrer Anwendung sicher und bei einfachen Migrationen ohne großen Aufwand ändern.

Im nächsten Artikel konzentrieren wir uns auf die Unterklasse von NSManagedObject. Wenn ein Core Data-Projekt irgendeine Komplexität aufweist, ist die Unterklasse NSManagedObject der richtige Weg.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.