Migrieren Sie Ihre Parse iOS-App zu Firebase

Wenn Sie ein Parse-Benutzer sind, der nach einer alternativen Backend-as-a-Service-Lösung sucht, ist Firebase möglicherweise die ideale Wahl für Ihre iOS-App.

Diese Anleitung beschreibt, wie Sie bestimmte Dienste in Ihre App integrieren. Grundlegende Anweisungen zur Firebase-Einrichtung finden Sie im Einrichtungsleitfaden für iOS+ .

Google Analytics

Google Analytics ist eine kostenlose App-Messlösung, die Einblicke in die App-Nutzung und das Nutzerengagement bietet. Analytics lässt sich in alle Firebase-Funktionen integrieren und bietet Ihnen unbegrenzte Berichte für bis zu 500 verschiedene Ereignisse, die Sie mit dem Firebase SDK definieren können.

Weitere Informationen finden Sie in der Google Analytics-Dokumentation .

Vorgeschlagene Migrationsstrategie

Die Verwendung verschiedener Analyseanbieter ist ein häufiges Szenario, das sich problemlos auf Google Analytics anwenden lässt. Fügen Sie es einfach zu Ihrer App hinzu, um von Ereignissen und Benutzereigenschaften zu profitieren, die Analytics automatisch erfasst, z. B. erstes Öffnen, App-Update, Gerätemodell, Alter.

Für benutzerdefinierte Ereignisse und Benutzereigenschaften können Sie eine doppelte Schreibstrategie anwenden, indem Sie sowohl Parse Analytics als auch Google Analytics verwenden, um Ereignisse und Eigenschaften zu protokollieren, wodurch Sie die neue Lösung schrittweise einführen können.

Code-Vergleich

Analysen analysieren

// Start collecting data
[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];

NSDictionary *dimensions = @{
  // Define ranges to bucket data points into meaningful segments
  @"priceRange": @"1000-1500",
  // Did the user filter the query?
  @"source": @"craigslist",
  // Do searches happen more often on weekdays or weekends?
  @"dayType": @"weekday"
};
// Send the dimensions to Parse along with the 'search' event
[PFAnalytics trackEvent:@"search" dimensions:dimensions];

Google Analytics

// Obtain the AppMeasurement instance and start collecting data
[FIRApp configure];

// Send the event with your params
[FIRAnalytics logEventWithName:@"search" parameters:@{
  // Define ranges to bucket data points into meaningful segments
  @"priceRange": @"1000-1500",
  // Did the user filter the query?
  @"source": @"craigslist",
  // Do searches happen more often on weekdays or weekends?
  @"dayType": @"weekday"
}];

Firebase-Echtzeitdatenbank

Die Firebase Realtime Database ist eine in der Cloud gehostete NoSQL-Datenbank. Daten werden als JSON gespeichert und in Echtzeit mit jedem verbundenen Client synchronisiert.

Weitere Informationen finden Sie in der Dokumentation zur Firebase-Echtzeitdatenbank .

Unterschiede bei Parse-Daten

Objekte

In Parse speichern Sie ein PFObject oder eine Unterklasse davon, das Schlüssel-Wert-Paare von JSON-kompatiblen Daten enthält. Die Daten sind schemalos, was bedeutet, dass Sie nicht angeben müssen, welche Schlüssel in jedem PFObject vorhanden sind.

Alle Firebase Realtime Database-Daten werden als JSON-Objekte gespeichert, und es gibt kein Äquivalent für PFObject ; Sie schreiben einfach in die JSON-Struktur Werte von Typen, die den verfügbaren JSON-Typen entsprechen.

Im Folgenden finden Sie ein Beispiel dafür, wie Sie die Highscores für ein Spiel speichern können.

Analysieren
PFObject *gameScore = [PFObject objectWithClassName:@"GameScore"];
gameScore[@"score"] = @1337;
gameScore[@"playerName"] = @"Sean Plott";
gameScore[@"cheatMode"] = @NO;
[gameScore saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
  if (succeeded) {
    // The object has been saved.
  } else {
    // There was a problem, check error.description
  }
}];
Firebase
// Create a reference to the database
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
NSString *key = [[ref child:@"scores"] childByAutoId].key;
NSDictionary *score = @{@"score": @1337,
                        @"playerName": @"Sean Plott",
                        @"cheatMode": @NO};
[key setValue:score withCompletionBlock:^(NSError *error,  FIRDatabaseReference *ref) {
  if (error) {
    // The object has been saved.
  } else {
    // There was a problem, check error.description
  }
}];
Weitere Informationen finden Sie im Handbuch zum Lesen und Schreiben von Daten auf Apple-Plattformen .

Beziehungen zwischen Daten

Ein PFObject kann eine Beziehung zu einem anderen PFObject haben: Jedes Objekt kann andere Objekte als Werte verwenden.

In der Firebase-Echtzeitdatenbank werden Beziehungen besser ausgedrückt, indem flache Datenstrukturen verwendet werden, die die Daten in separate Pfade aufteilen, sodass sie effizient in separaten Aufrufen heruntergeladen werden können.

Im Folgenden finden Sie ein Beispiel dafür, wie Sie die Beziehung zwischen Posts in einer Blogging-App und ihren Autoren strukturieren können.

Analysieren
// Create the author
PFObject *myAuthor = [PFObject objectWithClassName:@"Author"];
myAuthor[@"name"] = @"Grace Hopper";
myAuthor[@"birthDate"] = @"December 9, 1906";
myAuthor[@"nickname"] = @"Amazing Grace";

// Create the post
PFObject *myPost = [PFObject objectWithClassName:@"Post"];
myPost[@"title"] = @"Announcing COBOL, a New Programming Language";

// Add a relation between the Post and the Author
myPost[@"parent"] = myAuthor;

// This will save both myAuthor and myPost
[myPost saveInBackground];
Firebase
// Create a reference to the database
FIRDatabaseReference *ref = [[FIRDatabase database] reference];

// Create the author
NSString *myAuthorKey = @"ghopper";
NSDictionary *author = @{@"name": @"Grace Hopper",
                         @"birthDate": @"December 9, 1906",
                         @"nickname": @"Amazing Grace"};
// Save the author
[[ref child:myAuthorKey] setValue:author]

// Create and save the post
NSString *key = [[ref child:@"posts"] childByAutoId].key;
NSDictionary *post = @{@"author": myAuthorKey,
                       @"title": @"Announcing COBOL, a New Programming Language"};
[key setValue:post]

Das folgende Datenlayout ist das Ergebnis.

{
  // Info about the authors
  "authors": {
    "ghopper": {
      "name": "Grace Hopper",
      "date_of_birth": "December 9, 1906",
      "nickname": "Amazing Grace"
    },
    ...
  },
  // Info about the posts: the "author" fields contains the key for the author
  "posts": {
    "-JRHTHaIs-jNPLXOQivY": {
      "author": "ghopper",
      "title": "Announcing COBOL, a New Programming Language"
    }
    ...
  }
}
Weitere Einzelheiten finden Sie im Handbuch Strukturieren Sie Ihre Datenbank .

Lesen von Daten

In Parse lesen Sie Daten, indem Sie entweder die ID eines bestimmten Parse-Objekts verwenden oder Abfragen mit PFQuery ausführen.

In Firebase rufen Sie Daten ab, indem Sie einen asynchronen Listener an eine Datenbankreferenz anhängen. Der Listener wird einmal für den Anfangszustand der Daten und erneut ausgelöst, wenn sich die Daten ändern, sodass Sie keinen Code hinzufügen müssen, um festzustellen, ob sich die Daten geändert haben.

Im Folgenden finden Sie ein Beispiel dafür, wie Sie Spielstände für einen bestimmten Spieler abrufen können, basierend auf dem im Abschnitt „Objekte“ vorgestellten Beispiel.

Analysieren
PFQuery *query = [PFQuery queryWithClassName:@"GameScore"];
[query whereKey:@"playerName" equalTo:@"Dan Stemkoski"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
  if (!error) {
    for (PFObject *score in objects) {
      NSString *gameScore = score[@"score"];
      NSLog(@"Retrieved: %@", gameScore);
    }
  } else {
    // Log details of the failure
    NSLog(@"Error: %@ %@", error, [error userInfo]);
  }
}];
Firebase
// Create a reference to the database
FIRDatabaseReference *ref = [[FIRDatabase database] reference];

// This type of listener is not one time, and you need to cancel it to stop
// receiving updates.
[[[[ref child:@"scores"] queryOrderedByChild:@"playerName"] queryEqualToValue:@"Dan Stemkoski"]
    observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
  // This will fire for each matching child node.
  NSDictionary *score = snapshot.value;
  NSString gameScore = score[@"score"];
  NSLog(@"Retrieved: %@", gameScore);
}];
Weitere Informationen zu verfügbaren Arten von Ereignis-Listenern und zum Sortieren und Filtern von Daten finden Sie im Handbuch zum Lesen und Schreiben von Daten auf Apple-Plattformen .

Vorgeschlagene Migrationsstrategie

Überdenken Sie Ihre Daten

Die Firebase-Echtzeitdatenbank ist optimiert, um Daten in Millisekunden auf allen verbundenen Clients zu synchronisieren, und die resultierende Datenstruktur unterscheidet sich von den Parse-Kerndaten. Das bedeutet, dass der erste Schritt Ihrer Migration darin besteht, zu überlegen, welche Änderungen Ihre Daten erfordern, einschließlich:

  • Wie Ihre Parse-Objekte den Firebase-Daten zugeordnet werden sollen
  • Wenn Sie Eltern-Kind-Beziehungen haben, wie Sie Ihre Daten auf verschiedene Pfade aufteilen, damit sie effizient in separaten Aufrufen heruntergeladen werden können.

Migrieren Sie Ihre Daten

Nachdem Sie entschieden haben, wie Sie Ihre Daten in Firebase strukturieren, müssen Sie planen, wie Sie mit dem Zeitraum umgehen, in dem Ihre App in beide Datenbanken schreiben muss. Ihre Auswahlmöglichkeiten sind:

Hintergrundsynchronisierung

In diesem Szenario haben Sie zwei Versionen der App: die alte Version, die Parse verwendet, und eine neue Version, die Firebase verwendet. Synchronisierungen zwischen den beiden Datenbanken werden von Parse Cloud Code (Parse to Firebase) verarbeitet, wobei Ihr Code auf Änderungen in Firebase lauscht und diese Änderungen mit Parse synchronisiert. Bevor Sie die neue Version verwenden können, müssen Sie:

  • Konvertieren Sie Ihre vorhandenen Analysedaten in die neue Firebase-Struktur und schreiben Sie sie in die Firebase-Echtzeitdatenbank.
  • Schreiben Sie Parse-Cloud-Code-Funktionen, die die Firebase-REST-API verwenden, um Änderungen in die Firebase-Echtzeitdatenbank zu schreiben, die von alten Clients an den Parse-Daten vorgenommen wurden.
  • Schreiben und implementieren Sie Code, der auf Änderungen in Firebase lauscht und sie mit der Parse-Datenbank synchronisiert.

Dieses Szenario gewährleistet eine saubere Trennung von altem und neuem Code und hält die Clients einfach. Die Herausforderungen dieses Szenarios liegen im Umgang mit großen Datasets im anfänglichen Export und in der Sicherstellung, dass die bidirektionale Synchronisierung keine unendliche Rekursion erzeugt.

Doppeltes Schreiben

In diesem Szenario schreiben Sie eine neue Version der App, die sowohl Firebase als auch Parse verwendet, und verwenden Parse Cloud Code, um Änderungen, die von alten Clients vorgenommen wurden, von den Parse-Daten mit der Firebase-Echtzeitdatenbank zu synchronisieren. Wenn genügend Personen von der Nur-Parsing-Version der App migriert sind, können Sie den Parse-Code aus der Double-Write-Version entfernen.

Dieses Szenario erfordert keinen serverseitigen Code. Seine Nachteile sind, dass Daten, auf die nicht zugegriffen wird, nicht migriert werden und dass die Größe Ihrer App durch die Verwendung beider SDKs erhöht wird.

Firebase-Authentifizierung

Firebase Authentication kann Benutzer mithilfe von Passwörtern und beliebten föderierten Identitätsanbietern wie Google, Facebook und Twitter authentifizieren. Es bietet auch UI-Bibliotheken, um Ihnen die erheblichen Investitionen zu ersparen, die erforderlich sind, um eine vollständige Authentifizierungserfahrung für Ihre App auf allen Plattformen zu implementieren und aufrechtzuerhalten.

Weitere Informationen finden Sie in der Dokumentation zur Firebase-Authentifizierung .

Unterschiede bei Parse Auth

Parse stellt eine spezialisierte Benutzerklasse namens PFUser , die automatisch die für die Verwaltung von Benutzerkonten erforderliche Funktionalität handhabt. PFUser ist eine Unterklasse des PFObject , was bedeutet, dass Benutzerdaten in den Parse Data verfügbar sind und wie jedes andere PFObject um zusätzliche Felder erweitert werden können.

Ein FIRUser hat einen festen Satz grundlegender Eigenschaften – eine eindeutige ID, eine primäre E-Mail-Adresse, einen Namen und eine Foto-URL –, die in der Benutzerdatenbank eines separaten Projekts gespeichert sind; diese Eigenschaften können vom Benutzer aktualisiert werden. Sie können dem FIRUser Objekt keine anderen Eigenschaften direkt hinzufügen; Stattdessen können Sie die zusätzlichen Eigenschaften in Ihrer Firebase-Echtzeitdatenbank speichern.

Im Folgenden finden Sie ein Beispiel dafür, wie Sie einen Benutzer registrieren und ein zusätzliches Telefonnummernfeld hinzufügen können.

Analysieren
PFUser *user = [PFUser user];
user.username = @"my name";
user.password = @"my pass";
user.email = @"email@example.com";

// other fields can be set just like with PFObject
user[@"phone"] = @"415-392-0202";

[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
  if (!error) {
    // Hooray! Let them use the app now.
  } else {
    // Something went wrong
    NSString *errorString = [error userInfo][@"error"];
  }
}];
Firebase
[[FIRAuth auth] createUserWithEmail:@"email@example.com"
                           password:@"my pass"
                         completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  if (!error) {
    FIRDatabaseReference *ref = [[FIRDatabase database] reference];
    [[[[ref child:@"users"] child:user.uid] child:@"phone"] setValue:@"415-392-0202"
  } else {
    // Something went wrong
    NSString *errorString = [error userInfo][@"error"];
  }
}];

Vorgeschlagene Migrationsstrategie

Konten migrieren

Um Benutzerkonten von Parse zu Firebase zu migrieren, exportieren Sie Ihre Benutzerdatenbank in eine JSON- oder CSV-Datei und importieren Sie die Datei dann mit dem Befehl auth:import der Firebase-CLI in Ihr Firebase-Projekt.

Exportieren Sie zunächst Ihre Benutzerdatenbank aus der Parse-Konsole oder Ihrer selbst gehosteten Datenbank. Eine aus der Parse-Konsole exportierte JSON-Datei könnte beispielsweise wie folgt aussehen:

{ // Username/password user
  "bcryptPassword": "$2a$10$OBp2hxB7TaYZgKyTiY48luawlTuYAU6BqzxJfpHoJMdZmjaF4HFh6",
  "email": "user@example.com",
  "username": "testuser",
  "objectId": "abcde1234",
  ...
},
{ // Facebook user
  "authData": {
    "facebook": {
      "access_token": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
      "expiration_date": "2017-01-02T03:04:05.006Z",
      "id": "1000000000"
    }
  },
  "username": "wXyZ987654321StUv",
  "objectId": "fghij5678",
  ...
}

Wandeln Sie dann die exportierte Datei in das für die Firebase-CLI erforderliche Format um. Verwenden Sie die objectId Ihrer Parse-Benutzer als localId Ihrer Firebase-Benutzer. Codieren Sie außerdem die bcryptPassword Werte von Parse mit base64 und verwenden Sie sie im Feld passwordHash . Beispielsweise:

{
  "users": [
    {
      "localId": "abcde1234",  // Parse objectId
      "email": "user@example.com",
      "displayName": "testuser",
      "passwordHash": "JDJhJDEwJE9CcDJoeEI3VGFZWmdLeVRpWTQ4bHVhd2xUdVlBVTZCcXp4SmZwSG9KTWRabWphRjRIRmg2",
    },
    {
      "localId": "fghij5678",  // Parse objectId
      "displayName": "wXyZ987654321StUv",
      "providerUserInfo": [
        {
          "providerId": "facebook.com",
          "rawId": "1000000000",  // Facebook ID
        }
      ]
    }
  ]
}

Importieren Sie schließlich die transformierte Datei mit der Firebase-CLI und geben Sie bcrypt als Hash-Algorithmus an:

firebase auth:import account_file.json --hash-algo=BCRYPT

Benutzerdaten migrieren

Wenn Sie zusätzliche Daten für Ihre Benutzer speichern, können Sie diese mithilfe der im Abschnitt Datenmigration beschriebenen Strategien in die Firebase Realtime Database migrieren. Wenn Sie Konten mithilfe des im Abschnitt zur Kontenmigration beschriebenen Ablaufs migrieren, haben Ihre Firebase-Konten dieselben IDs wie Ihre Parse-Konten, sodass Sie alle Beziehungen, die durch die Benutzer-ID verschlüsselt sind, problemlos migrieren und reproduzieren können.

Firebase Cloud Messaging

Firebase Cloud Messaging (FCM) ist eine plattformübergreifende Messaging-Lösung, mit der Sie Nachrichten und Benachrichtigungen zuverlässig und kostenlos übermitteln können. Der Notifications Composer ist ein kostenloser Dienst, der auf Firebase Cloud Messaging basiert und gezielte Benutzerbenachrichtigungen für Entwickler mobiler Apps ermöglicht.

Weitere Informationen finden Sie in der Firebase Cloud Messaging-Dokumentation .

Unterschiede zu Parse-Push-Benachrichtigungen

Jede Parse-Anwendung, die auf einem für Benachrichtigungen registrierten Gerät installiert ist, hat ein zugehöriges Installation , in dem Sie alle Daten speichern, die für gezielte Benachrichtigungen erforderlich sind. Installation ist eine Unterklasse von PFUser , was bedeutet, dass Sie Ihren Installation beliebige zusätzliche Daten hinzufügen können.

Der Notifications Composer stellt vordefinierte Benutzersegmente basierend auf Informationen wie App, App-Version und Gerätesprache bereit. Sie können mithilfe von Google Analytics-Ereignissen und -Eigenschaften komplexere Benutzersegmente erstellen, um Zielgruppen aufzubauen. Weitere Informationen finden Sie im Hilfeleitfaden für Zielgruppen . Diese Targeting-Informationen sind in der Firebase Realtime Database nicht sichtbar.

Vorgeschlagene Migrationsstrategie

Migrieren von Gerätetoken

Während Parse APNs-Gerätetoken verwendet, um gezielt Installationen für Benachrichtigungen zu benachrichtigen, verwendet FCM FCM-Registrierungstoken, die den APNs-Gerätetoken zugeordnet sind. Fügen Sie einfach das FCM SDK zu Ihrer Apple-App hinzu und es wird automatisch ein FCM-Token abgerufen .

Migrieren von Kanälen zu FCM-Themen

Wenn Sie Parse-Kanäle zum Senden von Benachrichtigungen verwenden, können Sie zu FCM-Themen migrieren, die dasselbe Publisher-Subscriber-Modell bereitstellen. Um den Übergang von Parse zu FCM zu handhaben, können Sie eine neue Version der App schreiben, die das Parse-SDK zum Abbestellen von Parse-Kanälen und das FCM-SDK zum Abonnieren der entsprechenden FCM-Themen verwendet.

Wenn Ihr Benutzer beispielsweise das Thema „Riesen“ abonniert hat, würden Sie Folgendes tun:

PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation removeObject:@"Giants" forKey:@"channels"];
[currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
  if (succedeed) {
    [[FIRMessaging messaging] subscribeToTopic:@"/topics/Giants"];
  } else {
    // Something went wrong unsubscribing
  }
}];

Mit dieser Strategie können Sie Nachrichten sowohl an den Parse-Kanal als auch an das entsprechende FCM-Thema senden und so Benutzer sowohl alter als auch neuer Versionen unterstützen. Wenn genügend Benutzer von der Nur-Parsing-Version der App migriert sind, können Sie diese Version beenden und mit dem Senden nur mit FCM beginnen.

Weitere Informationen finden Sie in den FCM-Themendokumenten .

Firebase-Remote-Konfiguration

Firebase Remote Config ist ein Clouddienst, mit dem Sie das Verhalten und Aussehen Ihrer App ändern können, ohne dass Benutzer ein App-Update herunterladen müssen. Wenn Sie Remote Config verwenden, erstellen Sie In-App-Standardwerte, die das Verhalten und Erscheinungsbild Ihrer App steuern. Anschließend können Sie später die Firebase-Konsole verwenden, um In-App-Standardwerte für alle App-Benutzer oder für Segmente Ihrer Benutzerbasis zu überschreiben.

Firebase Remote Config kann während Ihrer Migrationen sehr nützlich sein, wenn Sie verschiedene Lösungen testen und dynamisch mehr Clients zu einem anderen Anbieter verschieben möchten. Wenn Sie beispielsweise eine Version Ihrer App haben, die sowohl Firebase als auch Parse für die Daten verwendet, könnten Sie eine zufällige Perzentilregel verwenden, um zu bestimmen, welche Clients von Firebase lesen, und den Prozentsatz schrittweise erhöhen.

Weitere Informationen zu Firebase Remote Config finden Sie in der Remote Config-Einführung .

Unterschiede zu Parse Config

Mit Parse config können Sie Schlüssel/Wert-Paare zu Ihrer App auf dem Parse Config Dashboard hinzufügen und dann die PFConfig auf dem Client abrufen. Jede PFConfig Instanz, die Sie erhalten, ist immer unveränderlich. Wenn Sie in Zukunft eine neue PFConfig aus dem Netzwerk abrufen, ändert sie keine vorhandene PFConfig Instanz, sondern erstellt stattdessen eine neue und stellt sie über currentConfig zur Verfügung.

Mit Firebase Remote Config erstellen Sie In-App-Standardwerte für Schlüssel/Wert-Paare, die Sie von der Firebase-Konsole aus überschreiben können, und Sie können Regeln und Bedingungen verwenden, um Variationen der Benutzererfahrung Ihrer App für verschiedene Segmente Ihrer Benutzerbasis bereitzustellen. Firebase Remote Config implementiert eine Singleton-Klasse, die die Schlüssel/Wert-Paare für Ihre App verfügbar macht. Anfänglich gibt der Singleton die Standardwerte zurück, die Sie in der App definieren. Sie können jederzeit einen neuen Wertesatz vom Server abrufen, der für Ihre App geeignet ist. Nachdem der neue Satz erfolgreich abgerufen wurde, können Sie auswählen, wann er aktiviert werden soll, um die neuen Werte für die App verfügbar zu machen.

Vorgeschlagene Migrationsstrategie

Sie können zu Firebase Remote Config wechseln, indem Sie die Schlüssel/Wert-Paare Ihrer Parse-Konfiguration in die Firebase-Konsole kopieren und dann eine neue Version der App bereitstellen, die Firebase Remote Config verwendet.

Wenn Sie sowohl mit Parse Config als auch mit Firebase Remote Config experimentieren möchten, können Sie eine neue Version der App bereitstellen, die beide SDKs verwendet, bis genügend Benutzer von der Nur-Parse-Version migriert sind.

Code-Vergleich

Analysieren

[PFConfig getConfigInBackgroundWithBlock:^(PFConfig *config, NSError *error) {
  if (!error) {
    NSLog(@"Yay! Config was fetched from the server.");
  } else {
    NSLog(@"Failed to fetch. Using Cached Config.");
    config = [PFConfig currentConfig];
  }

  NSString *welcomeMessage = config[@"welcomeMessage"];
  if (!welcomeMessage) {
    NSLog(@"Falling back to default message.");
    welcomeMessage = @"Welcome!";
  }
}];

Firebase

FIRRemoteConfig remoteConfig = [FIRRemoteConfig remoteConfig];
// Set defaults from a plist file
[remoteConfig setDefaultsFromPlistFileName:@"RemoteConfigDefaults"];

[remoteConfig fetchWithCompletionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {
  if (status == FIRRemoteConfigFetchStatusSuccess) {
    NSLog(@"Yay! Config was fetched from the server.");
    // Once the config is successfully fetched it must be activated before newly fetched
    // values are returned.
    [self.remoteConfig activateFetched];
  } else {
    NSLog(@"Failed to fetch. Using last fetched or default.");
  }
}];

// ...

// When this is called, the value of the latest fetched and activated config is returned;
// if there's none, the default value is returned.
NSString welcomeMessage = remoteConfig[@"welcomeMessage"].stringValue;