2010-03-11 3 views
5

Betrachten Sie eine iPhone-Anwendung, die ein Katalog von Tieren ist. Die Anwendung sollte dem Benutzer erlauben, benutzerdefinierte Informationen für jedes Tier hinzuzufügen - sagen wir mal eine Bewertung (auf einer Skala von 1 bis 5), sowie einige Notizen, die sie über das Tier eingeben können. Der Benutzer wird jedoch nicht in der Lage sein, die Tierdaten selbst zu ändern. Angenommen, die Aktualisierung der Anwendung sollte für den (statischen) Katalogteil leicht zu ändern sein, aber wir möchten, dass der (dynamische) benutzerdefinierte Benutzerinformationsteil zwischen den Aktualisierungen beibehalten wird, so dass der Benutzer keinen verliert ihre benutzerdefinierten Informationen.iPhone und Core Data: Wie man vom Benutzer eingegebene Daten zwischen Updates speichert?

Wir würden wahrscheinlich Core Data verwenden, um diese App zu bauen. Lassen Sie uns auch sagen, dass wir bereits einen vorherigen Prozess zum Einlesen von Tierdaten haben, um den Backing-Speicher (SQLite), den Core Data verwendet, vorzufüllen. Wir können diese Datenbankdatei in das Anwendungsbündel selbst einbetten, da sie nicht modifiziert wird. Wenn ein Benutzer ein Update auf die Anwendung herunterlädt, enthält die neue Version die neueste (statische) Tierkatalog-Datenbank, so dass wir uns keine Sorgen machen müssen, dass sie veraltet ist.

Aber jetzt der knifflige Teil: Wie speichern wir die (dynamischen) benutzerdefinierten Benutzerdaten auf eine solide Art und Weise?

Mein erster Gedanke ist, dass die (dynamische) Datenbank im Documents-Verzeichnis für die App gespeichert werden sollte, so dass Anwendungsupdates die vorhandenen Daten nicht verfälschen. Hab ich recht?

Mein zweiter Gedanke ist, dass, da die (dynamische) benutzerdefinierte Benutzerdaten-Datenbank nicht im selben Speicher wie der (statische) Tierkatalog ist, wir nicht naiv eine Beziehung zwischen den Rating- und den Notes-Entitäten herstellen können (in einem Datenbank) und die Animal-Entität (in der anderen Datenbank). In diesem Fall würde ich mir eine Lösung vorstellen, eine String-Eigenschaft "animalName" in der Entität Rating/Notes zu haben und sie zur Laufzeit abzugleichen. Ist dies der beste Weg, oder gibt es eine Möglichkeit, zwei verschiedene Datenbanken in Core Data zu "synchronisieren"?

+0

@ Shaggy Frog ... Ich habe jetzt das gleiche Problem. Ich sehe, dass Ihre Lösung eine korrekte Lösung ist, um dieses Problem zu lösen, aber ich würde gerne wissen, ob Sie einen besseren Weg gefunden haben, dies zu tun. Danke für die Lösung trotzdem. es ist die beste Hilfe, die ich bis jetzt gefunden habe. – learner2010

+0

@ user621808 Die einzige Problemumgehung wäre, die Datenbank nicht jedes Mal neu zu erstellen, wenn ich die Daten aktualisiere. Mit anderen Worten, erstellen Sie es genau einmal und bearbeiten Sie es dann manuell, wenn Sie hinzufügen/löschen/bearbeiten müssen. –

Antwort

2

Hier ist im Grunde, wie ich das gelöst habe.

Während die Antworten von Amorya und MHarrison gültig waren, hatten sie eine Annahme: Nach der Erstellung würden nicht nur die Tabellen, sondern auch jede Zeile in jeder Tabelle immer gleich sein.

Das Problem ist, dass mein Prozess zum Vorfüllen der "Animals" -Datenbank unter Verwendung vorhandener Daten (die regelmäßig aktualisiert werden) jedes Mal eine neue Datenbankdatei erstellt. Mit anderen Worten, ich kann mich nicht darauf verlassen, eine Beziehung zwischen der (statischen) Animal-Entität und einer (dynamischen) Rating-Entität in Core Data zu erstellen, da diese Entität möglicherweise nicht existiert, wenn ich die Anwendung das nächste Mal neu generiere. Warum nicht? Weil ich keine Kontrolle darüber habe, wie Core Data diese Beziehung hinter den Kulissen speichert. Da es sich um einen SQLite-Backing-Store handelt, verwendet es wahrscheinlich eine Tabelle mit Fremdschlüsselbeziehungen. Aber wenn Sie die Datenbank neu generieren, können Sie nicht davon ausgehen, welche Werte jede Zeile für einen Schlüssel erhält. Der Primärschlüssel für Lion kann beim zweiten Mal anders sein, wenn ich einen Lemur zur Liste hinzugefügt habe.

Die einzige Möglichkeit, dieses Problem zu vermeiden, würde voraussetzen, die Datenbank nur einmal zu füllen und dann die Zeilen bei jedem Update manuell zu aktualisieren. Allerdings ist diese Art von Prozess in meinem Fall nicht wirklich möglich.

Also, was ist die Lösung? Nun, da ich mich nicht auf die Fremdschlüsselbeziehungen verlassen kann, die Core Data macht, muss ich mir meine eigenen ausdenken. Was ich mache, ist ein Zwischenschritt in meinem Datenbankgenerierungsprozess: Anstatt meine Rohdaten (die zufällig UTF-8-Text sind, sondern MS Word-Dateien sind) zu erstellen und die SQLite-Datenbank mit Core Data direkt zu erstellen, führe ich einen Intermediär ein Schritt: Ich konvertiere die .txt in .xml. Warum XML? Nun, nicht weil es eine Wunderwaffe ist, sondern einfach weil es ein Datenformat ist, das ich sehr leicht analysieren kann. Was hat diese XML-Datei also anders? Ein Hash-Wert, den ich für jedes Tier unter Verwendung von MD5 erzeuge, ist einzigartig. Wofür ist der Hashwert? Nun, ich kann jetzt zwei Datenbanken erstellen: eine für die "statischen" Animal-Daten (für die ich bereits einen Prozess habe), und eine für die "dynamische" Ratings-Datenbank, die die iPhone-App erstellt und die sich im Verzeichnis Dokumente der Anwendung befindet . Für jede Bewertung erstelle ich eine Pseudo-Beziehung mit dem Tier, indem ich den Hash-Wert der Tier-Entität speichere. Jedes Mal, wenn der Benutzer eine Animal-Detailansicht auf dem iPhone aufruft, frage ich die "dynamische" Datenbank ab, um festzustellen, ob eine Rating-Entität existiert, die dem Animal.md5Hash-Wert entspricht.

Da ich diese intermediate XML-Datei speichern, das nächste Mal, wenn es ein Update gibt, kann ich es gegen die letzte XML-Datei vergleichen, die ich verwendet habe, um zu sehen, was geändert wurde. Wenn nun der Name eines Tieres geändert wurde - sagen wir, ein Tippfehler wurde korrigiert -, stelle ich den Hash-Wert für dieses Tier in situ wieder her. Dies bedeutet, dass selbst wenn ein Tiername geändert wird, ich immer noch in der "dynamischen" Datenbank ein passendes Rating finden kann, falls es existiert.

Diese Lösung hat einen weiteren schönen Nebeneffekt: Ich muss keine Migrationsprobleme behandeln. Die mit der App ausgelieferte "static" Animal-Datenbank kann als App-Ressource eingebettet bleiben. Es kann alles ändern, was es will. Die "dynamische" Bewertungsdatenbank muss möglicherweise zu einem bestimmten Zeitpunkt migriert werden, wenn ich das Datenmodell so modifiziere, dass weitere Entitäten hinzugefügt werden, die beiden Datenmodelle jedoch tatsächlich vollständig unabhängig bleiben.

1

Die Art, wie ich das mache ist: eine Datenbank der statischen Sachen als Teil Ihres App-Pakets zu liefern. Überprüfen Sie beim Start der App, ob in Documents eine Datenbankdatei vorhanden ist. Wenn nicht, kopiere den aus dem App-Bundle in Dokumente. Öffnen Sie dann die Datenbank aus den Dokumenten: Dies ist die einzige, die Sie lesen und bearbeiten.

Wenn ein Upgrade durchgeführt wurde, muss der neue statische Inhalt mit der bearbeitbaren Datenbank des Benutzers zusammengeführt werden. Jedes statische Element (in Ihrem Fall Animal) hat ein Feld namens factoryID, das eine eindeutige Kennung ist. Beim ersten Start nach einem Update laden Sie die Datenbank aus dem App-Bundle und durchlaufen jedes Animal. Suchen Sie für jeden den entsprechenden Datensatz in der Arbeitsdatenbank und aktualisieren Sie alle Felder nach Bedarf.

Es kann eine schnellere Lösung geben, aber da der Upgrade-Prozess nicht zu oft passiert, sollte die Zeit nicht zu problematisch sein.

+0

Aber das würde erfordern, dass der Prozess, der die Datenbank vorab füllt, nicht jedes Mal eine neue Datenbank von Grund auf erstellen kann, richtig? Das ist sicherlich möglich, aber nicht so einfach, da dieser Prozess nicht mehr "staatenlos" ist. –

1

Das Speichern Ihrer SQLite-Datenbank im Documents-Verzeichnis (NSDocumentDirectory) ist sicherlich der richtige Weg. Im Allgemeinen sollten Sie Anwendungsänderungen vermeiden, die SQL-Tabellen so weit wie möglich ändern oder löschen (Hinzufügen ist in Ordnung). Wenn Sie jedoch eine Änderung in einem Update vornehmen müssen, würde etwas wie das, was Amorya gesagt hat, funktionieren: Öffnen Sie die alte DB, importieren Sie, was Sie brauchen, in die neue DB und löschen Sie die alte.

Da es so klingt, als ob Sie eine statische Datenbank mit einer "Animal" -Tabelle wünschen, die nicht geändert werden kann, sollte das Ersetzen dieser Tabelle durch Upgrades kein Problem sein - solange die ID der Einträge nicht stimmt. t ändern. Die Art und Weise, wie Sie Benutzerdaten über Tiere speichern, besteht darin, für jeden vom Benutzer erstellten Eintrag eine Beziehung mit einem Fremdschlüssel zu einer Tier-ID zu erstellen. Dies ist, was Sie migrieren müssten, wenn ein Upgrade es ändert.

+0

Ich habe dieses Problem auch. Ich muss herausfinden, wie man der Benutzerdatenbank ein paar Zeilen mehr hinzufügt.Die v2-Datenbank mit den neuen Zusätzen für die App wird für neue Installationen kopiert, aber ich muss die Zusätze zur sql-Datenbank im Verzeichnis des Benutzers für Leute hinzufügen, die v1 installiert haben. Wie mache ich das? Ich habe seit ein paar Wochen gesucht und kann nicht den Code finden, um es zu tun. – RyeMAC3