Erste Schritte mit Cloud Firestore für iOS

Mobile Codierer nutzen seit vielen Jahren die Firebase Realtime Database (Mobile Backend as a Service (MBaaS) -Plattform) von Google und helfen ihnen, sich auf die Entwicklung von Features für ihre Apps zu konzentrieren, ohne sich um die Back-End-Infrastruktur und -Datenbank kümmern zu müssen. Durch die einfache Speicherung und Speicherung von Daten in der Cloud sowie die Gewährleistung von Authentifizierung und Sicherheit ermöglicht Firebase den Codierern, sich auf die Clientseite zu konzentrieren. 

Im vergangenen Jahr kündigte Google mit Cloud Firestore eine weitere Back-End-Datenbanklösung an, die von Grund auf mit dem Versprechen einer größeren Skalierbarkeit und Intuitivität ausgestattet wurde. Dies führte jedoch zu einiger Verwirrung hinsichtlich seines Platzes in Bezug auf das bereits bestehende Flaggschiffprodukt von Google, die Firebase Realtime Database. In diesem Lernprogramm werden die Unterschiede zwischen den beiden Plattformen und die jeweiligen Vorteile erläutert. Sie erfahren, wie Sie mit Firestore-Dokumentreferenzen arbeiten, Daten lesen, schreiben, aktualisieren und löschen, indem Sie eine einfache Erinnerungs-App erstellen.

Ziele dieses Tutorials

In diesem Lernprogramm werden Sie Cloud Firestore vorgestellt. Sie erfahren, wie Sie die Plattform für die Persistenz und Synchronisierung der Datenbank in Echtzeit nutzen können. Wir werden die folgenden Themen behandeln:

  • Was ist Cloud Firestore?
  • das Firestore-Datenmodell
  • Cloud Firestore einrichten
  • Erstellen und Arbeiten mit Cloud Firestore-Referenzen
  • Lesen von Daten in Echtzeit von Cloud Firestore
  • Daten erstellen, aktualisieren und löschen
  • Filterung und zusammengesetzte Abfragen

Angenommenes Wissen

In diesem Lernprogramm wird davon ausgegangen, dass Sie mit Firebase vertraut waren und sich mit Swift und Xcode entwickelt haben.

Was ist Cloud Firestore??

Wie die Firebase Realtime Database bietet Firestore mobilen und Web-Entwicklern eine plattformübergreifende Cloud-Lösung, mit der Daten unabhängig von Netzwerklatenz oder Internetkonnektivität in Echtzeit gespeichert werden können, sowie nahtlose Integration mit der Google Cloud Platform-Suite. Neben diesen Ähnlichkeiten gibt es verschiedene Vor- und Nachteile, die sich voneinander unterscheiden. 

Datenmodell

Grundsätzlich werden in der Echtzeitdatenbank Daten in einem großen, monolithischen, hierarchischen JSON-Baum gespeichert, wohingegen Firestore Daten in Dokumenten und Sammlungen sowie in Untersammlungen organisiert. Dies erfordert weniger Denormalisierung. Das Speichern von Daten in einem JSON-Baum hat den Vorteil der Einfachheit, wenn mit einfachen Datenanforderungen gearbeitet wird. Bei der Arbeit mit komplexeren hierarchischen Daten wird dies jedoch umständlicher. 

Offline-Unterstützung

Beide Produkte bieten Offline-Unterstützung, indem Daten aktiv in Warteschlangen zwischengespeichert werden, wenn latente oder keine Netzwerkkonnektivität vorhanden ist, um lokale Änderungen möglichst im Back-End zu synchronisieren. Firestore unterstützt die Offline-Synchronisierung für Web-Apps zusätzlich zu mobilen Apps, wohingegen die Echtzeitdatenbank nur die mobile Synchronisierung ermöglicht.

Abfragen und Transaktionen 

Die Echtzeitdatenbank unterstützt nur begrenzte Sortier- und Filterfunktionen. Sie können nur auf Eigenschaftsebene, jedoch nicht beides, in einer einzelnen Abfrage sortieren oder filtern. Abfragen sind ebenfalls tief, dh sie geben einen großen Teilbaum der Ergebnisse zurück. Das Produkt unterstützt nur einfache Schreib- und Transaktionsvorgänge, für die ein Rückruf für die Fertigstellung erforderlich ist. 

Firestore hingegen führt Indexabfragen mit zusammengesetzter Sortierung und Filterung ein, sodass Sie Aktionen kombinieren können, um Kettenfilter und Sortierung zu erstellen. Sie können auch flache Abfragen ausführen, um Untersammlungen anstelle der gesamten Sammlung zurückzugeben, die Sie mit der Echtzeitdatenbank erhalten würden. Transaktionen sind atomarer Natur, unabhängig davon, ob Sie einen Batch-Vorgang oder einen Einzelvorgang senden. Die Transaktionen werden automatisch wiederholt, bis sie abgeschlossen sind. Darüber hinaus unterstützt die Echtzeitdatenbank nur einzelne Schreibtransaktionen, während Firestore Batch-Vorgänge atomar ermöglicht.

Leistung und Skalierbarkeit

Die Echtzeitdatenbank ist, wie Sie es erwarten würden, ziemlich robust und hat geringe Latenzzeiten. Datenbanken sind jedoch auf einzelne Regionen beschränkt, vorbehaltlich der Verfügbarkeit von Zonen. Firestore hingegen beherbergt Daten horizontal über mehrere Zonen und Regionen hinweg, um weltweite Verfügbarkeit, Skalierbarkeit und Zuverlässigkeit zu gewährleisten. In der Tat hat Google versprochen, dass Firestore zuverlässiger ist als die Echtzeitdatenbank. 

Ein weiteres Manko der Echtzeitdatenbank ist die Beschränkung auf 100.000 gleichzeitige Benutzer (100.000 gleichzeitige Verbindungen und 1.000 Schreibvorgänge / Sekunde in einer einzigen Datenbank). Danach müssen Sie Ihre Datenbank aufteilen (Aufteilen der Datenbank in mehrere Datenbanken), um mehr Benutzer zu unterstützen . Firestore skaliert automatisch über mehrere Instanzen hinweg, ohne dass Sie eingreifen müssen. 

Firestore wurde von Grund auf für Skalierbarkeit entwickelt und verfügt über eine neue schematische Architektur, die Daten über mehrere Regionen hinweg repliziert, sich um die Authentifizierung kümmert und andere sicherheitsrelevante Aspekte innerhalb des clientseitigen SDKs erledigt. Das neue Datenmodell ist intuitiver als das von Firebase und ähnelt eher anderen vergleichbaren NoSQL-Datenbanklösungen wie MongoDB, während es eine robustere Abfrage-Engine bietet. 

Sicherheit 

Schließlich verwaltet die Echtzeitdatenbank, wie Sie aus unseren vorherigen Tutorials wissen, die Sicherheit durch Kaskadierungsregeln mit separaten Validierungstriggern. Dies funktioniert mit Firebase-Datenbankregeln, die Ihre Daten separat überprüfen. Auf der anderen Seite bietet Firestore ein einfacheres, jedoch leistungsfähigeres Sicherheitsmodell, das die Cloud Firestore-Sicherheitsregeln und das Identity and Access Management (IAM) nutzt, wobei die Datenvalidierung automatisch ausgenommen wird.

Das Firestore-Datenmodell

Firestore ist eine dokumentenbasierte NoSQL-Datenbank, die aus Dokumentensammlungen besteht, von denen jedes Daten enthält. Da es sich um eine NoSQL-Datenbank handelt, erhalten Sie keine Tabellen, Zeilen und andere Elemente, die Sie in einer relationalen Datenbank finden würden, sondern Gruppen von Schlüssel / Wert-Paaren, die Sie in Dokumenten finden würden. 

Sie erstellen Dokumente und Sammlungen implizit, indem Sie einem Dokument Daten zuweisen. Wenn das Dokument oder die Sammlung nicht vorhanden ist, werden sie automatisch für Sie erstellt, da die Sammlung immer der Stammknoten (erster Knoten) sein muss. Hier ist ein einfaches Beispielschema für Aufgaben des Projekts, an dem Sie in Kürze arbeiten werden. Es besteht aus der Aufgabensammlung sowie zahlreichen Dokumenten mit zwei Feldern, dem Namen (String) und einem Kennzeichen, ob die Aufgabe erledigt ist (boolean)..

Lassen Sie uns jedes der Elemente zerlegen, damit Sie sie besser verstehen können. 

Sammlungen

Sammlungen, die mit Datenbanktabellen in der SQL-Welt synonym sind, enthalten ein oder mehrere Dokumente. Sammlungen müssen die Stammelemente in Ihrem Schema sein und dürfen nur Dokumente enthalten, keine anderen Sammlungen. Sie können jedoch auf ein Dokument verweisen, das sich wiederum auf Sammlungen (Unterkollektionen) bezieht..

Im obigen Diagramm besteht eine Aufgabe aus zwei primitiven Feldern (Name und erledigt) sowie einer Unterauflistung (Unteraufgabe), die aus zwei eigenen primitiven Feldern besteht. 

Unterlagen

Dokumente bestehen aus Schlüssel / Wert-Paaren, wobei die Werte einen der folgenden Typen haben: 

  • primitive Felder (z. B. Zeichenfolgen, Zahlen, Boolean)
  • komplexe verschachtelte Objekte (Listen oder Arrays von Primitiven)
  • Untersammlungen

Verschachtelte Objekte werden auch als Maps bezeichnet und können innerhalb des Dokuments wie folgt dargestellt werden. Das folgende Beispiel zeigt ein verschachteltes Objekt bzw. ein verschachteltes Array:

ID: 2422892 // primitiver Name: "Denken Sie daran, Milch zu kaufen" Detail: // geschachtelte Objektnotizen: "Dies ist eine Aufgabe, um Milch aus dem Geschäft zu kaufen" erstellt: 2017-04-09 falsche Benachrichtigung: ["2F22-89R2", "L092-G623", "H00V-T4S1"]… 

Weitere Informationen zu den unterstützten Datentypen finden Sie in der Dokumentation zu Datentypen von Google. Als Nächstes richten Sie ein Projekt für die Arbeit mit Cloud Firestore ein.

Einrichten des Projekts

Wenn Sie bereits mit Firebase gearbeitet haben, sollten Ihnen viele davon bekannt sein. Andernfalls müssen Sie ein Konto in Firebase erstellen und den Anweisungen im Abschnitt "Einrichten des Projekts" in unserem vorherigen Tutorial "Erste Schritte mit Firebase-Authentifizierung für iOS" folgen . 

Um diesem Tutorial zu folgen, klonen Sie das Tutorial-Projekt-Repo. Fügen Sie anschließend die Firestore-Bibliothek mit einfüge folgendes zu deinem hinzu Poddatei:

pod 'Firebase / Core' pod 'Firebase / Firestore'

Geben Sie in Ihrem Terminal Folgendes ein, um Ihre Bibliothek zu erstellen:

pod installieren

Wechseln Sie als Nächstes zu Xcode und öffnen Sie die .xcworkspace Datei. Navigieren Sie zu AppDelegate.swift Datei und geben Sie in der Anwendung: didFinishLaunchingWithOptions: Methode:

FirebaseApp.configure ()

Gehen Sie in Ihrem Browser zur Firebase-Konsole und wählen Sie die Option Datenbank Tab links. 

Stellen Sie sicher, dass Sie die Option auswählen Starten Sie im Testmodus Sie haben also keine Sicherheitslücken, während wir experimentieren, und beachten Sie die Sicherheitshinweise, wenn Sie Ihre App in die Produktion bringen. Sie können jetzt eine Sammlung und einige Beispieldokumente erstellen.

Sammlung und Beispieldokument hinzufügen

Erstellen Sie zunächst eine erste Sammlung, Aufgaben, durch die Auswahl von Sammlung hinzufügen Schaltfläche und Benennung der Sammlung, wie unten dargestellt:

Für das erste Dokument lassen Sie die Dokument-ID leer, wodurch automatisch eine ID für Sie generiert wird. Das Dokument besteht einfach aus zwei Feldern: Name und erledigt.

Speichern Sie das Dokument, und Sie sollten die Sammlung und das Dokument zusammen mit der automatisch generierten ID bestätigen können:

Wenn die Datenbank mit einem Beispieldokument in der Cloud eingerichtet ist, können Sie mit der Implementierung des Firestore SDK in Xcode beginnen.

Erstellen und Arbeiten mit Datenbankreferenzen

Öffne die MasterViewController.swift Datei in Xcode und fügen Sie die folgenden Zeilen hinzu, um die Bibliothek zu importieren:

importieren Sie die Firebase-Klasse MasterViewController: UITableViewController @IBOutlet schwach var addButton: UIBarButtonItem! private var-Dokumente: [DocumentSnapshot] = [] public var-Aufgaben: [Task] = [] privater var-Listener: ListenerRegistration!… 

Hier erstellen Sie einfach eine Listener-Variable, mit der Sie bei einer Änderung in Echtzeit eine Verbindung zur Datenbank auslösen können. Sie erstellen auch eine DocumentSnapshot Referenz, die den temporären Daten-Snapshot enthält.

Bevor Sie mit dem View-Controller fortfahren, erstellen Sie eine weitere schnelle Datei, Task.Schalten, welches Ihr Datenmodell repräsentiert:

Foundation-Struktur importieren Task Variablenname: Zeichenfolge Var erledigt: Bool-Variablennummer: Zeichenfolge Var-Verzeichnis: [String: Beliebig] return ["Name": Name, "Fertig": Fertig] Erweiterung Task Init? (Wörterbuch: [String: Any], ID: String) Guard let Name = Wörterbuch ["Name"] als? String, let done = Wörterbuch ["done"] als? Bool else return nil self.init (name: name, done: done, id: id)

Das obige Code-Snippet enthält eine Komfort-Eigenschaft (Wörterbuch) und eine Methode (init), die das Auffüllen des Modellobjekts erleichtern. Wechseln Sie wieder zum View-Controller, und deklarieren Sie eine globale Setter-Variable, die die Basisabfrage auf die Top 50-Einträge in der Aufgabenliste beschränkt. Sie werden auch den Listener entfernen, sobald Sie die Abfragevariable (siehe) festgelegt haben didSet Eigenschaft unten:

fileprivate func baseQuery () -> Query return Firestore.firestore (). collection ("Aufgaben"). limit (bis: 50) fileprivate var Abfrage: Abfrage? didSet if let listener = listener listener.remove () überschreiben func viewDidLoad () super.viewDidLoad () self.query = baseQuery () überschreiben func viewWillDisappear (_ animiert: Bool) super.viewWillDisappear ( animiert) self.listener.remove ()

Lesen von Daten in Echtzeit von Cloud Firestore

Wenn der Dokumentverweis vorhanden ist, in viewWillAppear (_animated: Bool), Verknüpfen Sie den zuvor erstellten Listener mit den Ergebnissen des Abfrage-Snapshots, und rufen Sie eine Liste von Dokumenten ab. Dazu rufen Sie die Firestore-Methode auf Abfrage? .addSnapshotListener:

self.listener = Abfrage? .addSnapshotListener (Dokumente, Fehler) in guard Lassen Sie Momentaufnahme = Dokumente else print ("Fehler beim Abrufen von Dokumentenergebnissen: \ (Fehler!)") return lassen Sie Ergebnisse = Momentaufnahme.documents.map (Dokument ) -> Task in if let task = Task (Dictionary: document.data (), id: document.documentID) Task zurückgeben else fatalError ("Initialisierung des Typs \ (Task.self) mit Dictionary \ (Dokument. data ()) ") self.tasks = Ergebnisse self.documents = snapshot.documents self.tableView.reloadData ()

Die obige Schließung weist den zu snapshot.documents indem Sie das Array iterativ abbilden und in ein neues umschließen Aufgabe Modellinstanzobjekt für jedes Datenelement im Schnappschuss. Mit wenigen Zeilen haben Sie also alle Aufgaben aus der Cloud erfolgreich eingelesen und der globalen zugewiesen AufgabenArray. 

Füllen Sie zur Anzeige der Ergebnisse Folgendes ausTabellenansichtDelegierungsmethoden:

func numberOfSections überschreiben (in tableView: UITableView) -> Int return 1 func tableView überschreiben (_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int return task.count override func tableView (_ tableView: UITableView, cellForRowAt indexPath) : IndexPath) -> UITableViewCell let cell = tableView.dequeueReusableCell (withIdentifier: "Cell" für: indexPath) let item = Aufgaben [indexPath.row] cell.textLabel! .Text = item.name cell.textLabel! .TextColor = item.done == falsch? UIColor.black: UIColor.lightGray-Rückgabezelle

In diesem Stadium sollten Sie das Projekt erstellen und ausführen, und im Simulator sollten Sie die Daten in Echtzeit beobachten können. Fügen Sie über die Firebase-Konsole Daten hinzu, und Sie sollten sie sofort im App-Simulator sehen. 

Daten erstellen, aktualisieren und löschen

Nach dem erfolgreichen Lesen von Inhalten aus dem Backend werden als Nächstes Daten erstellt, aktualisiert und gelöscht. Im nächsten Beispiel wird veranschaulicht, wie Daten aktualisiert werden. Verwenden Sie dazu ein künstliches Beispiel, in dem Sie ein Element nur durch Antippen der Zelle als erledigt markieren können. Beachten Sie das Sammlungsdokument (Artikel Identifikationsnummer) .updateData (["done":! item.done]) Schließungseigenschaft, die einfach auf eine bestimmte Dokument-ID verweist und jedes der Felder im Wörterbuch aktualisiert:

func tableView überschreiben (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) let item = Aufgaben [indexPath.row] let collection = Firestore.firestore (). collection ("Tasks") collection.document (item.id) .updateData ( ["done":! item.done,]) err in if let err = err print ("Fehler beim Aktualisieren des Dokuments: \ (err)") else print ("Dokument erfolgreich aktualisiert") tableView.reloadRows (at: [indexPath], mit: .automatic)

Um ein Element zu löschen, rufen Sie die dokumentieren(Artikel Identifikationsnummer).löschen() Methode:

Überschreiben von func tableView (_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool return true Überschreiben von func tableView (_ tableView: UITableView, CommiteditingStyle: UITableViewCellEditingStyle, forRowAt indexPath) if (editStarter). let item = Aufgaben [indexPath.row] _ = Firestore.firestore (). collection ("Aufgaben"). document (item.id) .delete ()

Um eine neue Aufgabe zu erstellen, müssen Sie eine neue Schaltfläche in Ihrem Storyboard hinzufügen und deren Schaltfläche verbinden IBAction an den View Controller, erstellen Sie ein addTask (_ sender :) Methode. Wenn ein Benutzer die Schaltfläche drückt, wird ein Warnblatt angezeigt, in dem der Benutzer einen neuen Tasknamen hinzufügen kann:

collection ("Tasks"). addDocument (data: ["name": textFieldReminder.text ?? "leere Task", "done": false]) 

Vervollständigen Sie den letzten Teil der App, indem Sie Folgendes eingeben:

@IBAction func addTask (_ sender: Any) let alertVC: UIAlertController = UIAlertController (Titel: "Neue Aufgabe", Nachricht: "Was möchten Sie sich merken?", BevorzugterStil: .alert) alertVC.addTextField (UITextField)  let cancelAction = UIAlertAction.init (Titel: "Cancel", Stil: .destructive, Handler: nil) alertVC.addAction (cancelAction) // Schließen der Alert-Aktion let addAction = UIAlertAction.init (Titel: "Add", Stil:. default) (UIAlertAction) -> Void in let textFieldReminder = (alertVC.textFields? .first)! als UITextField sei db = Firestore.firestore () var docRef: DocumentReference? = nil docRef = db.collection ("Tasks"). addDocument (data: ["name": textFieldReminder.text ?? "leere Task", "done": false]) err in, wenn err = err print ( "Fehler beim Hinzufügen des Dokuments: \ (err)") else print ("Dokument hinzugefügt mit ID: \ (docRef! .DocumentID)") alertVC.addAction (addAction) present (alertVC, animiert: wahr, Abschluss: null)

Erstellen Sie die App erneut und führen Sie sie erneut aus. Wenn der Simulator angezeigt wird, fügen Sie einige Aufgaben hinzu und markieren Sie einige als erledigt. Anschließend können Sie die Löschfunktion testen, indem Sie einige Aufgaben entfernen. Sie können bestätigen, dass die gespeicherten Daten in Echtzeit aktualisiert wurden, indem Sie zu Ihrer Firebase-Datenbankkonsole wechseln und die Sammlung und die Dokumente beobachten.

Filterung und zusammengesetzte Abfragen

Bisher haben Sie nur mit einer einfachen Abfrage gearbeitet, ohne spezielle Filterfunktionen. Um etwas robustere Abfragen zu erstellen, können Sie mithilfe von a nach bestimmten Werten filtern whereField Klausel:

docRef.whereField ("name", isEqualTo: searchString)

Sie können Ihre Abfragedaten bestellen und einschränken, indem Sie das verwenden Sortieren nach: ) und beschränken auf: ) Methoden wie folgt:

docRef.order (von: "name"). limit (5)

In der FirebaseDo-App haben Sie bereits Gebrauch gemacht Grenze mit der Basisabfrage. Im obigen Snippet haben Sie auch ein anderes Feature verwendet, Verbundabfragen, bei denen sowohl die Reihenfolge als auch das Limit miteinander verkettet sind. Sie können beliebig viele Abfragen verketten, wie im folgenden Beispiel:

docRef .whereField ("name", isEqualTo: searchString) .whereField ("done", isEqualTo: false) .order (von: "name") .limit (5)

Fazit

In diesem Lernprogramm haben Sie sich mit dem neuen MBaaS-Produkt von Google, Cloud Firestore, befasst. In diesem Prozess wurde eine einfache Taskerinnerungs-App erstellt, die zeigt, wie einfach es ist, Ihre Daten in der Cloud zu speichern, zu synchronisieren und abzufragen. Sie haben die Datenschemastruktur von Firestore im Vergleich zur Firebase-Echtzeitdatenbank kennen gelernt und erfahren, wie Sie Daten in Echtzeit lesen und schreiben sowie Daten aktualisieren und löschen. Sie haben auch gelernt, wie Sie einfache und zusammengesetzte Abfragen ausführen und Daten filtern. 

Cloud Firestore wurde mit dem Ziel entwickelt, die Robustheit der Firebase-Echtzeitdatenbank bereitzustellen, ohne dass die Einschränkungen, die Entwickler von Mobilgeräten erleiden mussten, insbesondere hinsichtlich Skalierbarkeit und Abfragen, bestand. Wir haben nur die Oberfläche von Firestore gekratzt. Es lohnt sich auf jeden Fall, einige der fortschrittlicheren Konzepte zu untersuchen, wie das Paginieren von Daten mit Abfrage-Cursors, das Verwalten von Indizes und das Sichern Ihrer Daten.