Meine iPhone-App muss ihren Kerndatenspeicher migrieren, und einige der Datenbanken sind ziemlich groß. In der Dokumentation von Apple wird vorgeschlagen, "mehrere Durchgänge" zum Migrieren von Daten zu verwenden, um die Speichernutzung zu reduzieren. Die Dokumentation ist jedoch sehr begrenzt und erklärt nicht sehr gut, wie dies tatsächlich zu tun ist. Kann mich jemand auf ein gutes Beispiel hinweisen oder detailliert erklären, wie man das tatsächlich schafft?
85
Antworten:
Ich habe herausgefunden, was Apple in seiner Dokumentation andeutet . Es ist eigentlich sehr einfach, aber noch ein langer Weg, bis es offensichtlich ist. Ich werde die Erklärung anhand eines Beispiels veranschaulichen. Die Ausgangssituation ist folgende:
Datenmodell Version 1
Dies ist das Modell, das Sie erhalten, wenn Sie ein Projekt mit der Vorlage "Navigationsbasierte App mit Kerndatenspeicher" erstellen. Ich habe es kompiliert und mit Hilfe einer for-Schleife hart getroffen, um ungefähr 2k Einträge mit unterschiedlichen Werten zu erstellen. Dort gehen wir 2.000 Ereignisse mit einem NSDate-Wert.
Jetzt fügen wir eine zweite Version des Datenmodells hinzu, die folgendermaßen aussieht:
Datenmodell Version 2
Der Unterschied ist: Die Event-Entität ist weg und wir haben zwei neue. Eine, in der ein Zeitstempel als
double
gespeichert ist, und die zweite, in der ein Datum als gespeichert werden sollNSString
.Ziel ist es, alle Ereignisse der Version 1 auf die beiden neuen Entitäten zu übertragen und die Werte während der Migration zu konvertieren. Dies führt zu doppelt so vielen Werten wie jeweils ein anderer Typ in einer separaten Entität.
Für die Migration wählen wir die Migration von Hand und dies mit Mapping-Modellen. Dies ist auch der erste Teil der Antwort auf Ihre Frage. Wir werden die Migration in zwei Schritten durchführen, da die Migration von 2k-Einträgen lange dauert und wir den Speicherbedarf gering halten möchten.
Sie können diese Zuordnungsmodelle sogar weiter aufteilen, um nur Bereiche der Entitäten zu migrieren. Angenommen, wir haben eine Million Datensätze. Dies kann den gesamten Prozess zum Absturz bringen. Es ist möglich, die abgerufenen Entitäten mit einem Filter-Prädikat einzugrenzen .
Zurück zu unseren beiden Mapping-Modellen.
Wir erstellen das erste Mapping-Modell wie folgt:
1. Neue Datei -> Ressource -> Zuordnungsmodell
2. Wählen Sie einen Namen, ich habe StepOne gewählt
3. Legen Sie das Quell- und Zieldatenmodell fest
Abbildung Modell Schritt Eins
Für die Multi-Pass-Migration sind keine benutzerdefinierten Entitätsmigrationsrichtlinien erforderlich. Wir werden dies jedoch tun, um in diesem Beispiel ein wenig mehr Details zu erhalten. Daher fügen wir der Entität eine benutzerdefinierte Richtlinie hinzu. Dies ist immer eine Unterklasse von
NSEntityMigrationPolicy
.Diese Richtlinienklasse implementiert einige Methoden, um unsere Migration durchzuführen. In diesem Fall ist es jedoch einfach, sodass wir nur eine Methode implementieren müssen :
createDestinationInstancesForSourceInstance:entityMapping:manager:error:
.Die Implementierung sieht folgendermaßen aus:
StepOneEntityMigrationPolicy.m
Letzter Schritt: die Migration selbst
Ich überspringe den Teil zum Einrichten des zweiten Mapping-Modells, das fast identisch ist, nur ein timeIntervalSince1970, mit dem das NSDate in ein Double konvertiert wird.
Schließlich müssen wir die Migration auslösen. Ich werde den Boilerplate-Code vorerst überspringen. Wenn Sie es brauchen, werde ich hier posten. Sie finden es unter Anpassen des Migrationsprozesses. Es ist nur eine Zusammenführung der ersten beiden Codebeispiele. Der dritte und letzte Teil werden wie folgt geändert: Anstatt die Klassenmethode der
NSMappingModel
Klasse zu verwenden, verwendenmappingModelFromBundles:forSourceModel:destinationModel:
wir die,initWithContentsOfURL:
da die Klassenmethode nur ein, möglicherweise das erste gefundene Zuordnungsmodell im Bundle zurückgibt.Jetzt haben wir die beiden Zuordnungsmodelle, die in jedem Durchgang der Schleife verwendet werden können und die Migrationsmethode an den Migrationsmanager senden. Das ist es.
Anmerkungen
Ein Mapping-Modell endet im
cdm
Bundle.Der Zielspeicher muss angegeben werden und sollte nicht der Quellspeicher sein. Sie können nach erfolgreicher Migration die alte löschen und die neue umbenennen.
Ich habe nach der Erstellung der Mapping-Modelle einige Änderungen am Datenmodell vorgenommen. Dies führte zu einigen Kompatibilitätsfehlern, die ich nur mit der Neuerstellung der Mapping-Modelle beheben konnte.
quelle
Diese Fragen hängen zusammen:
Speicherprobleme beim Migrieren großer CoreData-Datenspeicher auf dem iPhone
Migration von Core-Daten mit mehreren Durchläufen in Chunks mit iOS
Um den ersten Link zu zitieren:
quelle
Angenommen, Ihr Datenbankschema enthält 5 Entitäten, z. B. Person, Schüler, Kurs, Klasse und Registrierung, um das Standardbeispiel zu verwenden, bei dem der Schüler die Unterklassen Person, Klasse implementiert Kurs und Registrierung Klasse und Schüler verbindet. Wenn Sie Änderungen an all diesen Tabellendefinitionen vorgenommen haben, müssen Sie bei den Basisklassen beginnen und sich nach oben arbeiten. Sie können also nicht mit der Konvertierung von Registrierungen beginnen, da jeder Registrierungsdatensatz davon abhängt, ob Klasse und Schüler dort sind. Sie beginnen also damit, nur die Personentabelle zu migrieren, vorhandene Zeilen in die neue Tabelle zu kopieren, die neuen Felder (falls möglich) auszufüllen und die entfernten Spalten zu verwerfen. Führen Sie jede Migration innerhalb eines Autorelease-Pools durch, damit Ihr Speicher wieder gestartet werden kann.
Sobald die Personentabelle fertig ist, können Sie die Schülertabelle konvertieren. Dann hüpfen Sie zu Kurs und dann Klasse und schließlich zur Registrierungstabelle.
Die andere Überlegung ist die Anzahl der Datensätze. Wenn wie Person tausend Zeilen hätte, müssten Sie etwa alle 100 das NSManagedObject-Äquivalent einer Version ausführen, um den Kontext des verwalteten Objekts mitzuteilen [moc refreshObject: ob mergeChanges: NEIN]; Stellen Sie außerdem Ihren veralteten Daten-Timer auf einen niedrigen Wert ein, damit der Speicher häufig geleert wird.
quelle