Daten auf Apple-Plattformen lesen und schreiben

Optional: Prototyp erstellen und mit Firebase Local Emulator Suite testen

Bevor du darauf sprichst, wie deine App Daten aus dem Realtime Database liest und schreibt, stellen wir Ihnen eine Reihe von Tools vor, mit denen Sie Realtime Database-Prototypen erstellen und testen können. Funktion: Firebase Local Emulator Suite. Wenn Sie verschiedene Daten ausprobieren, Modelle zu erstellen, Sicherheitsregeln zu optimieren oder eine kostengünstige Möglichkeit für die Interaktion mit dem Backend, da die Möglichkeit, lokal zu arbeiten, ohne Live-Dienste bereitzustellen, ist das eine gute Idee.

Ein Realtime Database-Emulator ist Teil der Local Emulator Suite, die ermöglicht es Ihrer App, mit dem Inhalt und der Konfiguration Ihrer emulierten Datenbank zu interagieren, sowie optional Ihre emulierten Projektressourcen (Funktionen, andere Datenbanken, und Sicherheitsregeln).

Zur Verwendung des Realtime Database-Emulators sind nur wenige Schritte erforderlich:

  1. Fügen Sie der Testkonfiguration Ihrer App eine Codezeile hinzu, um eine Verbindung zum Emulator herzustellen.
  2. Führen Sie im Stammverzeichnis Ihres lokalen Projektverzeichnisses firebase emulators:start aus.
  3. Über den Prototypcode Ihrer App über eine Realtime Database-Plattform Aufrufe ausführen oder die Realtime Database REST API verwenden.

Eine detaillierte Schritt-für-Schritt-Anleitung zu Realtime Database und Cloud Functions findest du. Sehen Sie sich auch die Local Emulator SuiteEinführung an.

FIRDatabaseReference abrufen

Zum Lesen oder Schreiben von Daten aus der Datenbank benötigen Sie eine Instanz von FIRDatabaseReference:

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

Hinweis: Dieses Firebase-Produkt ist nicht im App Clip-Ziel verfügbar.
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

Daten schreiben

In diesem Dokument werden die Grundlagen zum Lesen und Schreiben von Firebase-Daten behandelt.

Firebase-Daten werden in eine Database-Referenz geschrieben und von Anhängen eines asynchronen Listeners an die Referenz. Der Listener wird einmal für den anfänglichen Status der Daten und dann bei jeder Änderung der Daten ausgelöst.

Grundlegende Schreibvorgänge

Für einfache Schreibvorgänge können Sie setValue verwenden, um Daten in einem bestimmten referenzieren, wodurch alle unter diesem Pfad vorhandenen Daten ersetzt werden. Sie können diese Methode für Folgendes verwenden:

  • Karten-/Tickettypen, die den verfügbaren JSON-Typen entsprechen:
    • NSString
    • NSNumber
    • NSDictionary
    • NSArray

So können Sie beispielsweise einen Nutzer mit setValue hinzufügen:

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
self.ref.child("users").child(user.uid).setValue(["username": username])

Objective-C

Hinweis: Dieses Firebase-Produkt ist nicht im App Clip-Ziel verfügbar.
[[[self.ref child:@"users"] child:authResult.user.uid]
    setValue:@{@"username": username}];

Wenn Sie setValue auf diese Weise verwenden, werden Daten am angegebenen Speicherort überschrieben. einschließlich aller untergeordneten Knoten. Sie können ein untergeordnetes Konto jedoch auch ohne das gesamte Objekt umschreiben. Wenn Sie Nutzern erlauben möchten, ihre Profile zu aktualisieren könnten Sie den Nutzernamen wie folgt aktualisieren:

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
self.ref.child("users/\(user.uid)/username").setValue(username)

Objective-C

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
[[[[_ref child:@"users"] child:user.uid] child:@"username"] setValue:username];

Daten lesen

Daten durch Warten auf Wertereignisse lesen

Um Daten in einem Pfad zu lesen und auf Änderungen zu warten, verwenden Sie den observeEventType:withBlock von FIRDatabaseReference zu beobachten FIRDataEventTypeValue Ereignisse.

Ereignistyp Normale Nutzung
FIRDataEventTypeValue Änderungen am gesamten Inhalt eines Pfads lesen und beobachten.

Mit dem Ereignis FIRDataEventTypeValue können Sie die Daten an einem bestimmten Pfad lesen, wie sie zum Zeitpunkt des Ereignisses vorhanden sind. Diese Methode wird einmal ausgelöst, wenn der Listener hinzugefügt wird, und jedes Mal, wenn die Daten einschließlich untergeordneter Elemente Änderungen. Dem Ereignis-Callback wird ein snapshot übergeben, das alle Daten Standort, einschließlich Kinderdaten. Wenn keine Daten vorhanden sind, gibt der Snapshot false, wenn Sie exists() aufrufen, und nil, wenn Sie das Attribut value lesen.

Das folgende Beispiel zeigt eine Blog-Anwendung für soziale Netzwerke, Details zu einem Beitrag aus der Datenbank:

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
refHandle = postRef.observe(DataEventType.value, with: { snapshot in
  // ...
})

Objective-C

Hinweis: Dieses Firebase-Produkt ist nicht im App Clip-Ziel verfügbar.
_refHandle = [_postRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
  NSDictionary *postDict = snapshot.value;
  // ...
}];

Der Listener empfängt eine FIRDataSnapshot, die die Daten am angegebenen Standort in der Datenbank zum Zeitpunkt des Ereignisses in der Property value. Ich kann die Werte dem entsprechenden nativen Typ zuweisen, z. B. NSDictionary. Wenn am Standort keine Daten vorhanden sind, lautet der value-Wert nil.

Daten einmal lesen

Einmal mit getData() lesen

Das SDK wurde entwickelt, um Interaktionen mit Datenbankservern zu verwalten, unabhängig davon, ob Ihre App online oder offline ist.

Im Allgemeinen sollten Sie die oben beschriebenen Methoden für Wert-Ereignisse verwenden, um Daten zu lesen und über Aktualisierungen der Daten aus dem Backend benachrichtigt zu werden. Diese Techniken die Nutzung und Abrechnung reduzieren. Außerdem sind sie für die bestmögliche sowohl online als auch offline.

Wenn Sie die Daten nur einmal benötigen, können Sie mit getData() einen Snapshot des Daten aus der Datenbank. Falls getData() das Produkt aus irgendeinem Grund nicht zurückgeben kann Serverwert prüft der Client den lokalen Speicher-Cache und gibt einen Fehler zurück wenn der Wert immer noch nicht gefunden wird.

Im folgenden Beispiel wird gezeigt, wie der öffentliche Nutzername eines Nutzers einmal aus der Datenbank abgerufen wird:

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
do {
  let snapshot = try await ref.child("users/\(uid)/username").getData()
  let userName = snapshot.value as? String ?? "Unknown"
} catch {
  print(error)
}

Objective-C

Hinweis: Dieses Firebase-Produkt ist nicht im App Clip-Ziel verfügbar.
NSString *userPath = [NSString stringWithFormat:@"users/%@/username", uid];
[[ref child:userPath] getDataWithCompletionBlock:^(NSError * _Nullable error, FIRDataSnapshot * _Nonnull snapshot) {
  if (error) {
    NSLog(@"Received an error %@", error);
    return;
  }
  NSString *userName = snapshot.value;
}];

Die unnötige Verwendung von getData() kann die Bandbreitennutzung erhöhen und zu Verlusten führen Dies lässt sich mit einem Echtzeit-Listener verhindern. oben.

Daten einmal mit einem Beobachter lesen

In einigen Fällen möchten Sie vielleicht, dass der Wert aus dem lokalen Cache zurückgegeben wird. anstatt auf dem Server nach einem aktualisierten Wert zu suchen. In diesen können Sie mit observeSingleEventOfType die Daten aus der lokalen Festplatten-Cache.

Dies ist nützlich für Daten, die nur einmal geladen werden müssen und dies wahrscheinlich nicht sich häufig ändern oder aktives Zuhören erfordern. Zum Beispiel hat die Blog-App in den vorherigen Beispielen verwendet diese Methode zum Laden von Nutzerprofilen, mit dem Verfassen eines neuen Beitrags beginnen:

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
let userID = Auth.auth().currentUser?.uid
ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { snapshot in
  // Get user value
  let value = snapshot.value as? NSDictionary
  let username = value?["username"] as? String ?? ""
  let user = User(username: username)

  // ...
}) { error in
  print(error.localizedDescription)
}

Objective-C

Hinweis: Dieses Firebase-Produkt ist nicht im App Clip-Ziel verfügbar.
NSString *userID = [FIRAuth auth].currentUser.uid;
[[[_ref child:@"users"] child:userID] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
  // Get user value
  User *user = [[User alloc] initWithUsername:snapshot.value[@"username"]];

  // ...
} withCancelBlock:^(NSError * _Nonnull error) {
  NSLog(@"%@", error.localizedDescription);
}];

Daten aktualisieren oder löschen

Bestimmte Felder aktualisieren

Wenn Sie gleichzeitig in bestimmte untergeordnete Elemente eines Knotens schreiben möchten, ohne andere untergeordnete Knoten zu überschreiben, verwenden Sie die Methode updateChildValues.

Wenn Sie updateChildValues aufrufen, können Sie untergeordnete Werte auf niedrigerer Ebene aktualisieren, indem Sie und gibt einen Pfad für den Schlüssel an. Wenn Daten bedarfsgerecht an mehreren Standorten gespeichert sind können Sie alle Instanzen dieser Daten Daten-Fan-out. Beispiel: In einer Social-Blogging-App kann ein Beitrag erstellt und gleichzeitig im Feed der letzten Aktivitäten und im Feed der Aktivitäten des Nutzers aktualisiert werden. Zu diesem Zweck Blogging-Anwendung Code wie den folgenden verwendet:

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
guard let key = ref.child("posts").childByAutoId().key else { return }
let post = ["uid": userID,
            "author": username,
            "title": title,
            "body": body]
let childUpdates = ["/posts/\(key)": post,
                    "/user-posts/\(userID)/\(key)/": post]
ref.updateChildValues(childUpdates)

Objective-C

Hinweis: Dieses Firebase-Produkt ist nicht im App Clip-Ziel verfügbar.
NSString *key = [[_ref child:@"posts"] childByAutoId].key;
NSDictionary *post = @{@"uid": userID,
                       @"author": username,
                       @"title": title,
                       @"body": body};
NSDictionary *childUpdates = @{[@"/posts/" stringByAppendingString:key]: post,
                               [NSString stringWithFormat:@"/user-posts/%@/%@/", userID, key]: post};
[_ref updateChildValues:childUpdates];

In diesem Beispiel wird childByAutoId verwendet, um einen Beitrag in dem Knoten zu erstellen, der Beiträge für alle Nutzer in /posts/$postid und rufen den Schlüssel gleichzeitig mit getKey() Mit dem Schlüssel kann dann ein zweiter Eintrag im Beiträge auf /user-posts/$userid/$postid.

Mit diesen Pfaden können Sie gleichzeitige Aktualisierungen für mehrere Standorte in JSON-Baum mit einem einzelnen Aufruf von updateChildValues an, wie in diesem Beispiel erstellt den neuen Beitrag an beiden Orten. So werden gleichzeitige Aktualisierungen durchgeführt sind atomar: Entweder sind alle Updates erfolgreich oder alle schlagen fehl.

Abschlussblock hinzufügen

Wenn Sie wissen möchten, wann ein Commit für Ihre Daten durchgeführt wurde, können Sie Vervollständigungsblock Für setValue und updateChildValues ist ein optionales Ergänzungsblock, der aufgerufen wird, wenn der Schreibvorgang in den Datenbank. Dieser Listener kann hilfreich sein, um zu verfolgen, welche Daten gespeichert wurden und welche noch synchronisiert werden. Wenn der Aufruf fehlgeschlagen ist, wird dem Listener ein Fehlerobjekt übergeben, das angibt, warum der Fehler aufgetreten ist.

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
do {
  try await ref.child("users").child(user.uid).setValue(["username": username])
  print("Data saved successfully!")
} catch {
  print("Data could not be saved: \(error).")
}

Objective-C

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
[[[_ref child:@"users"] child:user.uid] setValue:@{@"username": username} withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  if (error) {
    NSLog(@"Data could not be saved: %@", error);
  } else {
    NSLog(@"Data saved successfully.");
  }
}];

Daten löschen

Am einfachsten löschen Sie Daten, indem Sie removeValue auf eine Referenz zum Speicherort dieser Daten anwenden.

Zum Löschen können Sie auch nil als Wert für einen weiteren Schreibvorgang angeben. wie setValue oder updateChildValues. Mit dieser Technik können Sie mit updateChildValues, um mehrere untergeordnete Elemente in einem einzigen API-Aufruf zu löschen.

Listener trennen

Beobachter beenden die Datensynchronisierung nicht automatisch, wenn Sie ein ViewController Wenn ein Beobachter nicht richtig entfernt wird, werden weiterhin Daten mit dem lokalen Speicher synchronisiert. Wenn ein Beobachter nicht mehr benötigt wird, entfernen Sie ihn, indem Sie Den zugeordneten FIRDatabaseHandle der removeObserverWithHandle-Methode.

Wenn Sie einer Referenz einen Callback-Block hinzufügen, wird ein FIRDatabaseHandle zurückgegeben. Mit diesen Ziehpunkten kann der Callback-Block entfernt werden.

Wenn einer Datenbankreferenz mehrere Listener hinzugefügt wurden, wird jeder Listener wird aufgerufen, wenn ein Ereignis ausgelöst wird. Wenn Sie die Synchronisierung von Daten an diesem Speicherort beenden möchten, müssen Sie alle Beobachter an einem Speicherort entfernen, indem Sie die Methode removeAllObservers aufrufen.

Das Aufrufen von removeObserverWithHandle oder removeAllObservers für einen Listener geschieht Listener, die auf ihren untergeordneten Knoten registriert sind, werden nicht automatisch entfernt. müssen Sie auch diese Verweise oder Aliasse, um sie zu entfernen.

Daten als Transaktionen speichern

Wenn Sie mit Daten arbeiten, die durch gleichzeitige wie inkrementelle Zähler, können Sie mit einem Transaktionsvorgang Sie geben diesem Vorgang zwei Argumente: eine Aktualisierungsfunktion und ein optionales Argument. Callback für den Abschluss des Vorgangs. Die Aktualisierungsfunktion nimmt den aktuellen Status der Daten ein Argument und gibt den neuen gewünschten Status zurück, den Sie schreiben möchten.

In der Beispiel-App für soziales Bloggen könnten Sie Nutzern beispielsweise erlauben, Beiträge zu bewerten und die Anzahl der Bewertungen zu verfolgen. Dazu gehen Sie so vor:

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
ref.runTransactionBlock({ (currentData: MutableData) -> TransactionResult in
  if var post = currentData.value as? [String: AnyObject],
    let uid = Auth.auth().currentUser?.uid {
    var stars: [String: Bool]
    stars = post["stars"] as? [String: Bool] ?? [:]
    var starCount = post["starCount"] as? Int ?? 0
    if let _ = stars[uid] {
      // Unstar the post and remove self from stars
      starCount -= 1
      stars.removeValue(forKey: uid)
    } else {
      // Star the post and add self to stars
      starCount += 1
      stars[uid] = true
    }
    post["starCount"] = starCount as AnyObject?
    post["stars"] = stars as AnyObject?

    // Set value and report transaction success
    currentData.value = post

    return TransactionResult.success(withValue: currentData)
  }
  return TransactionResult.success(withValue: currentData)
}) { error, committed, snapshot in
  if let error = error {
    print(error.localizedDescription)
  }
}

Objective-C

Hinweis: Dieses Firebase-Produkt ist nicht im App Clip-Ziel verfügbar.
[ref runTransactionBlock:^FIRTransactionResult * _Nonnull(FIRMutableData * _Nonnull currentData) {
  NSMutableDictionary *post = currentData.value;
  if (!post || [post isEqual:[NSNull null]]) {
    return [FIRTransactionResult successWithValue:currentData];
  }

  NSMutableDictionary *stars = post[@"stars"];
  if (!stars) {
    stars = [[NSMutableDictionary alloc] initWithCapacity:1];
  }
  NSString *uid = [FIRAuth auth].currentUser.uid;
  int starCount = [post[@"starCount"] intValue];
  if (stars[uid]) {
    // Unstar the post and remove self from stars
    starCount--;
    [stars removeObjectForKey:uid];
  } else {
    // Star the post and add self to stars
    starCount++;
    stars[uid] = @YES;
  }
  post[@"stars"] = stars;
  post[@"starCount"] = @(starCount);

  // Set value and report transaction success
  currentData.value = post;
  return [FIRTransactionResult successWithValue:currentData];
} andCompletionBlock:^(NSError * _Nullable error,
                       BOOL committed,
                       FIRDataSnapshot * _Nullable snapshot) {
  // Transaction completed
  if (error) {
    NSLog(@"%@", error.localizedDescription);
  }
}];

Durch die Verwendung einer Transaktion wird verhindert, dass die Anzahl der Sterne falsch ist, wenn mehrere Nutzer gleichzeitig dieselbe Markierung setzen oder der Client veraltete Daten hat. Der in der FIRMutableData-Klasse enthaltene Wert ist anfangs der letzte bekannte Wert des Clients für den Pfad oder nil, falls keiner vorhanden ist. Der Server vergleicht den ursprünglichen Wert mit dem aktuellen Wert und akzeptiert die Transaktion, wenn die Werte übereinstimmen, oder lehnt sie ab. Wenn die Transaktion abgelehnt wird, gibt der Server dem Client, der die Transaktion erneut mit der Methode aktualisierter Wert. Dies wird so lange wiederholt, bis die Transaktion akzeptiert wurde, oder zu viele es wurden Versuche unternommen.

Atomare serverseitige Increments

Im obigen Anwendungsfall schreiben wir zwei Werte in die Datenbank: die ID den Nutzer, der den Beitrag mit einem Stern markiert bzw. die Markierung aufhebt, und die dazugehörende Anzahl von Sternen Wenn wir dass der Nutzer den Beitrag markiert, können wir ein atomares Inkrement verwenden, statt einer Transaktion.

Swift

Hinweis: Dieses Firebase-Produkt ist für das App-Clip-Ziel nicht verfügbar.
let updates = [
  "posts/\(postID)/stars/\(userID)": true,
  "posts/\(postID)/starCount": ServerValue.increment(1),
  "user-posts/\(postID)/stars/\(userID)": true,
  "user-posts/\(postID)/starCount": ServerValue.increment(1)
] as [String : Any]
Database.database().reference().updateChildValues(updates)

Objective-C

Hinweis: Dieses Firebase-Produkt ist nicht im App Clip-Ziel verfügbar.
NSDictionary *updates = @{[NSString stringWithFormat: @"posts/%@/stars/%@", postID, userID]: @TRUE,
                        [NSString stringWithFormat: @"posts/%@/starCount", postID]: [FIRServerValue increment:@1],
                        [NSString stringWithFormat: @"user-posts/%@/stars/%@", postID, userID]: @TRUE,
                        [NSString stringWithFormat: @"user-posts/%@/starCount", postID]: [FIRServerValue increment:@1]};
[[[FIRDatabase database] reference] updateChildValues:updates];

Dieser Code verwendet keinen Transaktionsvorgang, daher wird er nicht automatisch erstellt bei einem Update noch einmal ausführen. Da der Inkrementierungsvorgang jedoch direkt auf dem Datenbankserver erfolgt, besteht kein Konflikt.

Wenn Sie anwendungsspezifische Konflikte erkennen und ablehnen möchten, z. B. einen bereits mit einem Stern markierten Beitrag markiert, sollten Sie benutzerdefinierte Sicherheitsregeln für diesen Anwendungsfall.

Offline mit Daten arbeiten

Wenn ein Client die Netzwerkverbindung verliert, funktioniert deine App weiterhin korrekt sind.

Jeder Client, der mit einer Firebase-Datenbank verbunden ist, verwaltet seine eigenen internen Versionen aller aktiven Daten. Beim Schreiben von Daten werden sie in diese lokale Version geschrieben. . Der Firebase-Client synchronisiert diese Daten dann mit der Remotedatenbank. mit anderen Clients auf Best-Effort-Basis zu verstehen.

Daher werden alle Schreibvorgänge in der Datenbank sofort als lokale Ereignisse ausgelöst, bevor Daten auf den Server geschrieben werden. Das bedeutet, dass Ihre App reaktionsschnell und unabhängig von der Netzwerklatenz oder Konnektivität.

Sobald die Verbindung wiederhergestellt ist, erhält Ihre App die entsprechenden um eine Synchronisierung mit dem aktuellen Serverstatus zu ermöglichen, benutzerdefinierten Code schreiben.

Weitere Informationen zum Offlineverhalten finden Sie unter Weitere Informationen zu Online- und Offlinefunktionen.

Nächste Schritte