GraphQL iOS: Verwendung von Cloud-Funktionen in einer Swift-App
In diesem Artikel habe ich Ihnen gezeigt, wie Sie GraphQL mit NodeJS Cloud Code in Back4app verwenden können.
Und in dieser Anleitung habe ich Ihnen gezeigt, wie Sie Apollo GraphQL iOS Client mit Swift verwenden.
Jetzt wollen wir das alles zusammenbringen und viele komplizierte Operationen mit wirklich einfachem Code realisieren. Und lassen wir XCode automatisch jeden API-Code für uns generieren, auch wenn wir die Klasse wechseln.
Klingt gut? Dann holen Sie sich einen Kaffee und legen Sie los!
Contents
- 1 Bevor Sie beginnen…
- 2 Ein paar Softwareprogramme, die uns helfen werden…
- 3 Erstellen unserer Klassen
- 4 Bring Cloud Code mit, Baby!
- 5 Testen… Testen…
- 6 Etwas XCoding
- 7 Unsere GraphQL-Datei
- 8 Etwas Swift-Code
- 9 Los geht’s!
- 10 Schlussfolgerung
- 11 Mit welcher Software können Cloud-Funktionen in der Swift-App genutzt werden?
- 12 Was ist die Magie von NPM?
Bevor Sie beginnen…
Sie benötigen ein Back4app-Konto mit einer erstellten App. Wenn Sie noch keinen haben, folgen Sie dieser Anleitung und Sie haben alles im Handumdrehen.
Ein paar Softwareprogramme, die uns helfen werden…
Wir werden auch ein paar Dinge verwenden, um die Dinge zu beschleunigen.
Natürlich können Sie das alles auch manuell erledigen, aber ich empfehle diesen Weg nicht, besonders nicht für Anfänger.
Wenn Sie Pakete manuell hinzufügen, müssen Sie sie auch manuell pflegen, was nach einiger Zeit lästig werden kann.
Sie müssen nicht unbedingt die Paketmanager verwenden, die ich hier vorstelle, aber ich empfehle Ihnen dringend, zumindest einige Paketmanager zu verwenden, anstatt die Pakete manuell zu verwalten. Wie ich schon sagte, kann die manuelle Verwaltung mit der Zeit etwas schwierig werden.
Ich werde Cocoapods für die Verwaltung von iOS-Paketen und NPM für die Verwaltung von Desktop-Paketen verwenden, aber auch hier gilt: Sie können verwenden, was Ihnen gefällt.
Eine Anleitung für die Installation von Cocoapods finden Sie auf dieser Website.
Eine Anleitung für die Installation von NPM finden Sie auf dieser Seite.
Erstellen unserer Klassen
Wir werden 3 Klassen einführen: Besitzer, Hund und Rasse.
Unser Modell wird das implizieren:
- Ein Besitzer kann mehrere Hunde haben
- Ein Hund kann nur eine Rasse haben.
Unsere Eigenschaften werden sein:
- Besitzer
- Name (Zeichenfolge)
- Alter (Zahl)
- Adresse (Zeichenkette)
- hasDogs (Relation zu Hund, da ein Besitzer mehrere Hunde haben kann)
- Hund
- Name (Zeichenkette)
- Geburtstag (Datum)
- Rasse (Zeiger auf Rasse, da ein Hund nur eine Rasse hat)
- Rasse
- Name (Zeichenfolge
Erstellen Sie diese Klassen grafisch oder programmatisch und füllen Sie sie mit einigen Daten. Meine Klassen sahen wie folgt aus:
Rasse
Hund
Besitzer
Bring Cloud Code mit, Baby!
Zeit für etwas Cloud Code. Aber dieses Mal möchte ich auch tiefer in das Thema einsteigen.
Habe ich Ihnen schon einmal gesagt, dass Cloud Code mit NPM-Modulen kompatibel ist? Das ist er! Und es kann Ihnen eine Menge Zeit ersparen!
Kennen Sie diese coolen Funktionen, die Sie gerne hätten, die aber schon jemand anderes gemacht hat? Nun, wenn es ein NPM-Modul ist, können Sie es verwenden!
Es gibt bereits einen Artikel über die Verwendung von Modulen in diesem Tutorial. Für diese Implementierung werde ich Moment verwenden, damit wir den Geburtstag eines Hundes nutzen und sein Alter in Monaten berechnen können.
Meine package.json-Datei wird also wie folgt aussehen:
{ "dependencies": { "moment": "*" } }
Das * bedeutet, dass ich die neueste Version verwenden werde.
Mein Cloud-Code sah am Ende so aus wie unten. Er ist gut kommentiert, so dass ich hier nicht ins Detail gehen werde, aber Sie können in der allerersten Zeile sehen, dass ich das Moment NPM-Modul verwende:
// Instantiierung des Moment-NPM-Moduls const moment = require('moment') Parse.Cloud.define("retrieveOwnersOrderedByAgeDescending", async req => { /* Diese Funktion ruft alle Eigentümer, geordnet nach Alter absteigend, ab. Wenn es keine Besitzer gibt, wird ein leeres Array abgerufen. */ const query = new Parse.Query("Owner"); query.descending("Alter") const results = await query.find(); Ergebnisse zurückgeben; }); Parse.Cloud.define("retrieveAllGermanShepherds", async req => { /* Diese Funktion ruft alle Hunde ab, die die Rasse "Deutscher Schäferhund" haben. Alle Eigenschaften der Hunde werden abgerufen. Wenn es keine Hunde gibt, wird ein leeres Array abgerufen. */ const breedQuery = new Parse.Query("Rasse"); breedQuery.equalTo("Name", "Deutscher Schäferhund") const Abfrage = new Parse.Abfrage("Hund"); query.matchesQuery("Rasse", breedQuery); const results = await query.find(); Ergebnisse zurückgeben; }); Parse.Cloud.define("retrieveDogIncludingBreedByName", async req => { /* Diese Funktion ruft die spezifischen Hundedetails einschließlich der Details zu den Rassen (Name) nach Hundenamen ab. Alle Eigenschaften des Hundes und der Rasse werden abgerufen. Wenn es keine Hunde gibt, wird null abgerufen. */ const query = new Parse.Query("Hund"); query.equalTo("name", req.params.name); query.include("Rasse") const results = await query.find(); Ergebnisse zurückgeben; }); Parse.Cloud.define("retrieveDogsNamesWithAgesInMonths", async req => { /* Diese Funktion ruft die Hundenamen ab, wobei die Eigenschaft "Geburtstag" mithilfe des NPM-Moduls in Monate umgewandelt wird. Es werden nur die Namen der Hunde abgerufen und das Alter in Monaten berechnet. Wenn es keine Hunde gibt, wird ein leeres Array abgerufen. */ let dogs = []; const query = new Parse.Query("Hund"); const results = await query.find(); for (let i = 0; i < results.length; i ++){ // Berechnung des Alters in Monaten unter Verwendung des NPM-Moduls Moment let ageInMonths = moment.duration(moment().diff(results[i].get("birthday"))).humanize(); let newDog = { "Hundename": results[i].get("Name"), "dogAgeInMonths": ageInMonths } dogs.push(newDog); } return dogs; });
Meine schema.graphql-Datei, in der meine vier Methoden beschrieben sind, sieht folgendermaßen aus
extend type Query { getAllOwnersAgeDescending: [OwnerClass!]! @resolve(to: "retrieveOwnersOrderedByAgeDescending") getAllGermanShepherds: [DogClass!]! @resolve(to: "retrieveAllGermanShepherds") getThisDogWithBreed (name:String): [DogClass!]! @resolve(to: "retrieveDogIncludingBreedByName") getDogsAgesInMonths: [DogAge!]! @resolve(to: "retrieveDogsNamesWithAgesInMonths") } type DogAge { Hundename: String. dogAgeInMonths: String! }
Wenn Sie die Syntax nicht verstehen, lesen Sie diesen Artikel im Abschnitt “Ein kleiner Zusatzschritt”.
Beachten Sie einfach das [DogAge!]! bei getDogsAgesInMonths. Da ich ein vom System generiertes Objekt abrufe, hat es kein Schema, das von GraphQL interpretiert werden kann, also muss ich auch den Typ erstellen, damit unser Client ihn interpretieren kann.
Testen… Testen…
Zeit für ein paar Tests!
Gehen wir zu unserer Parse GraphQL Console und führen wir unsere Abfragen aus, um die Ergebnisse zu überprüfen:
Abfrage für getAllOwnersAgeDescending:
query{ getAllOwnersAgeDescending { Name Alter Adresse } }
Abfrage für getAllGermanShepherds:
Abfrage { getAllGermanShepherds { Name Geburtstag } }
Abfrage für getThisDogWithBreed:
Abfrage{ getThisDogWithBreed(Name: "Fido"){ Name: Geburtstag Rasse{ Name } } }
Abfrage für getDogsAgesInMonths:
query{ getDogsAgesInMonths }
Alles funktioniert! Super! Jetzt ist es Zeit für…
Etwas XCoding
Wir haben alles, was wir von Back4app brauchen, eingerichtet und am Laufen. Jetzt ist es an der Zeit, das in XCode zu nutzen.
Diese Anleitung hat gezeigt, wie man das macht, aber dieses Mal sind wir etwas fortgeschrittener: wir haben mehrere Methoden, eine davon erwartet Variablen, also müssen wir ein paar Änderungen vornehmen.
Wenn Sie diesen Artikel noch nicht gelesen haben, empfehle ich Ihnen, dies nachzuholen, da er sehr detailliert ist.
Beginnen wir damit, die Anwendung zu erstellen und den Apollo-Client zu installieren, wie im Artikel beschrieben.
Danach öffnen Sie Ihre Main.storyboard-Datei, klicken Sie auf die Schaltfläche Objects in der oberen rechten Ecke und ziehen Sie eine Table View per Drag & Drop auf den View Controller:
Ändern Sie die Größe der Tabellenansicht so, dass sie der gesamten Ansicht des View Controllers entspricht, indem Sie die Ecken ziehen:
Und erstellen Sie Constraints für alle vier Seiten, indem Sie auf die Schaltfläche Neue Constraints hinzufügen unten rechts auf dem Bildschirm klicken. Klicken Sie auf die vier Seiten (rote Markierungen) und klicken Sie auf die Schaltfläche Neue Beschränkungen hinzufügen, um diese neuen Beschränkungen zuzuweisen:
Jetzt, wo die Tabellenansicht ausgewählt ist (klicken Sie darauf, um sie auszuwählen), fügen wir eine Prototypzelle hinzu. Klicken Sie auf den Attributinspektor oben rechts und ersetzen Sie die 0 durch eine 1 im Feld Prototypzellen:
Klicken Sie nun auf die neu erstellte Prototypzelle, um sie auszuwählen, und geben Sie ihr einen guten Bezeichner: “Zelle”.
Wir werden ihn später im Code verwenden, um diese Zelle zu identifizieren.
Jetzt müssen wir unsere Datenquelle und den Delegaten von der Tabellenansicht mit unserem View Controller verbinden.
Klicken Sie bei gedrückter Steuerungstaste auf die Tabellenansicht und ziehen Sie sie auf das gelbe Symbol am oberen Rand des View Controllers, auf dem View Controller steht, wenn Sie den Mauszeiger darüber bewegen.
Wenn Sie den Link Table View dort loslassen, wird ein kleines Popup angezeigt. Wählen Sie in dem Popup sowohl DataSource als auch Delegate:
Nun, das deckt die Grundlagen ab, aber wir müssen noch eine Aktualisierung der Tabellenansicht aufrufen, nachdem wir unsere Daten von Back4app abgerufen haben. Dazu müssen wir ein Outlet erstellen und es mit unserer Benutzeroberfläche verbinden.
Am einfachsten geht das, wenn Sie oben rechts auf dem Bildschirm auf Assistenteneditor anzeigen klicken, damit Sie die Benutzeroberfläche und den Code nebeneinander sehen können.
Klicken Sie dann mit der Steuerung auf Ihre Tabellenansicht und ziehen Sie sie auf den Code:
Wenn Sie loslassen, wird ein Popup-Fenster angezeigt. Füllen Sie den Namen aus und klicken Sie auf Verbinden:
Wenn Sie das getan haben, sollten Sie eine schöne Steckdose verbunden haben (beachten Sie den kleinen Kreis auf der Zeilennummer), so dass wir jetzt den Code für diese Tabellenansicht aufrufen können:
Wenn das alles erledigt ist, können wir zu unserer ViewController.swift-Datei gehen, denn es ist Zeit für…
Unsere GraphQL-Datei
In unserer GraphQL-Anleitung haben wir Ihnen gezeigt, wie Sie Ihre GraphQL-Datei erstellen können. Für dieses Projekt endete meine wie folgt:
query findAllOwners{ getAllOwnersAgeDescending{ Name Alter Adresse } } Abfrage findAllGermanShepherds{ getAllGermanShepherds { Name } } Abfrage findThisDog ($name: String!){ getThisDogWithBreed(name: $name){ Name: Geburtstag Rasse{ Name } } } Abfrage agesInMonths{ getDogsAgesInMonths }
Etwas Swift-Code
Auchhier haben wir bereits beschrieben, wie man Apollo in Swift konfiguriert, aber der heutige Code hat ein paar Änderungen.
Da wir die Daten in unserer Tabellenansicht grafisch darstellen werden, müssen wir zwei Methoden für unsere Datenquelle und den Delegaten einfügen, die ausgeführt werden sollen. Diese Methoden sind
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
und
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
Ich werde nicht viel dazu sagen, da diese Methoden im Code dokumentiert sind. Denken Sie einfach daran, dass diese beiden Methoden zwingend erforderlich sind, damit unsere Tabellenansicht funktioniert.
Ihr vollständiger Code sollte wie folgt aussehen:
// // ViewController.swift // GraphQLApollo // // Erstellt von Venom am 19/08/19. // Copyright © 2019 Venom. All rights reserved. // UIKit importieren Apollo importieren class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var tableView: UITableView! var list = [] as [String] // Dieses Array enthält die Werte, die wir anzeigen wollen // Apollo Client Initialisierung. // Mehr dazu hier: https://www.back4app.com/docs/ios/swift-graphql let apollo: ApolloClient = { let Konfiguration = URLSessionConfiguration.default configuration.httpAdditionalHeaders = [ "X-Parse-Application-Id": "lAcIOgR0ndd7R4uMqovhNAoudpi6tMsrOI9KCuyr", "X-Parse-Client-Key": "f1wwm6uWqQoxazys3QQrrtY4fKuQuxYvNYJmYQJP" ] let url = URL(string: "https://parseapi.back4app.com/graphql")! return ApolloClient( NetzwerkTransport: HTTPNetworkTransport( url: url, Konfiguration: Konfiguration ) ) }() override func viewDidLoad() { super.viewDidLoad() // Zusätzliche Einstellungen nach dem Laden der Ansicht vornehmen. apollo.fetch(query: FindAllOwnersQuery()) { result in guard let data = try? result.get().data else { return } for name in data.getAllOwnersAgeDescending { //Hängt jeden Namen für unser Listen-Array an self.list.append(name.name!) } //die folgende Zeile erzwingt ein Neuladen unserer Tabellenansicht, nachdem wir die Daten abgerufen haben DispatchQueue.main.async { self.tableView.reloadData() } } } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // Diese Funktion wird von unserer Tabellenansicht über die Datenquelle und den Delegaten aufgerufen. // Sie gibt lediglich die Anzahl der Objekte zurück, die in der Tabellenansicht angezeigt werden sollen. // Sie ist zwingend erforderlich, damit eine Tabellenansicht funktioniert. return list.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // Diese Funktion wird von unserer Tabellenansicht über die Datenquelle und den Delegaten aufgerufen. // Sie erstellt die anzuzeigenden Zellen mit dem im Storyboard festgelegten Bezeichner // Sie ist zwingend erforderlich, damit eine Tabellenansicht funktioniert. let cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "cell") cell.textLabel?.text = list[indexPath.row] return(cell) } }
Los geht’s!
Zeit, unseren Code auszuführen! Drücken Sie die Tastenkombination Command + R und wenn alles richtig ist, sollten Sie unsere Namen in der Tabellenansicht sehen:
Cool, nicht wahr?
Jetzt können wir sogar unseren Code ändern, um unsere anderen GraphQL-Methoden auszuführen und zu sehen, wie es funktionieren wird!
Ändern wir unsere GraphQL-Abfrage, um unsere Methode getAllGermanShepherds auszuführen:
override func viewDidLoad() { super.viewDidLoad() // Führen Sie alle zusätzlichen Einstellungen nach dem Laden der Ansicht durch. apollo.fetch(query: FindAllGermanShepherdsQuery()) { result in guard let data = try? result.get().data else { return } print(data.getAllGermanShepherds) for name in data.getAllGermanShepherds { //Hängt jeden Namen an unser Listen-Array an self.list.append(name.name!) } //die folgende Zeile erzwingt ein Neuladen unserer Tabellenansicht, nachdem wir die Daten abgerufen haben DispatchQueue.main.async { self.tableView.reloadData() } } }
und das Ergebnis…
Was, wenn wir eine Variable an unsere Abfrage übergeben wollen?
override func viewDidLoad() { super.viewDidLoad() // Führen Sie zusätzliche Einstellungen nach dem Laden der Ansicht durch. apollo.fetch(query: FindThisDogQuery(name: "Fido")) { result in guard let data = try? result.get().data else { return } print(data.getThisDogWithBreed) for name in data.getThisDogWithBreed { //Hängt jeden Namen an unser Listen-Array an self.list.append(name.name! + " - " + (Name.Rasse?.Name!)!) } //Die folgende Zeile erzwingt ein Neuladen unserer Tabellenansicht, nachdem wir die Daten abgerufen haben DispatchQueue.main.async { self.tableView.reloadData() } } }
Und jetzt wissen wir, dass Fido ein Mops ist:
Und was ist mit der Methode, die einen neuen Typ zurückgibt? Testen wir auch sie:
override func viewDidLoad() { super.viewDidLoad() // Führen Sie zusätzliche Einstellungen nach dem Laden der Ansicht durch. apollo.fetch(query: AgesInMonthsQuery()) { result in guard let data = try? result.get().data else { return } print(data.getDogsAgesInMonths) for dog in data.getDogsAgesInMonths { //Hängt jeden Namen für unser Listen-Array an self.list.append(hund.hundeName + " - " + hund.hundeAlterInMonaten) } //die folgende Zeile erzwingt ein Neuladen unserer Tabellenansicht, nachdem wir die Daten abgerufen haben DispatchQueue.main.async { self.tableView.reloadData() } } }
und das Ergebnis:
Schlussfolgerung
Cloud-Code ist cool. GraphQL ist supercool. Apollo verleiht Ihren nativen iOS-Applikationen eine neue Dimension der Genialität. Mit allen dreien zusammen haben Sie die Möglichkeit, sehr komplexe Anwendungen mit minimalem Aufwand zu erstellen.
Jetzt, da Sie in der Lage sind, einen voll funktionsfähigen Ablauf für eine App zu erstellen, der einfach zu erstellen und im Laufe der Zeit zu pflegen ist, stellt sich die Frage: Was werden Sie als nächstes erstellen?
Wir hoffen, dass Ihnen dieser Artikel gefallen hat! Wir haben bald mehr zu bieten! Bleiben Sie dran!
Mit welcher Software können Cloud-Funktionen in der Swift-App genutzt werden?
Es hängt von Ihrer Wahl ab. Verwenden Sie Software, die Sie einfach bedienen können. Ich habe die folgenden beiden in der obigen Praxis verwendet.
– Cocoapods für iOS-Paketverwaltung
– NPM für Desktop-Paketverwaltung
Was ist die Magie von NPM?
Cloud-Code ist mit NPM-Modulen kompatibel. Das ist großartig. Es spart Ihnen jede Menge Zeit und verschafft Ihnen einen Vorteil gegenüber Ihren Mitbewerbern. Die NPM-Kompatibilität mit Cloud-Codes verschafft Ihnen also einen entscheidenden Vorteil.