Bevor dieses Projekt abgeschlossen ist, machen wir noch zwei Änderungen. Zuerst fügen wir einen weiteren Tab zum UITabBarController
hinzu, der beliebte Petitionen anzeigen wird, und dann machen wir unseren Lade-Code ein bisschen widerstandsfähiger, indem wir Fehlermeldungen hinzufügen.
Wie ich bereits sagte, können wir den zweiten Tab nicht einfach in unser Storyboard setzen, da beide Tabs einen ViewController
beinhalten und das würde erfordern, dass die View Controller im Storyboard dupliziert werden müssten. Du kannst das machen, wenn du wirklich willst - aber bitte tu es nicht - es ist ein Wartungs-Albtraum!
Stattdessen lassen wir unsere Storyboard-Konfiguration in Ruhe und erzeugen den zweiten View Controller mit Hilfe von Code. So etwas hast du bisher noch nicht gemacht, aber es ist nicht schwierig und wir haben bereits den ersten Schritt getan, wie du sehen wirst.
Öffne die Datei AppDelegate.swift. Diese gab es schon in all unseren Projekten, aber bisher mussten wir noch nicht damit arbeiten. Suche nach der Methode didFinishLaunchingWithOptions
, die ziemlich weit oben in der Datei stehen sollte. Diese wird von iOS aufgerufen, wenn die App bereit zum Ausführen ist, und wir werden sie kapern, um einen zweiten ViewController
in unsere Tab Bar einzufügen.
Da sollte bereits einiges an vorgegebenem Apple-Code drin stehen, aber wir werden noch etwas mehr hinzufügen, und zwar direkt oberhalb der Zeile return true
:
if let tabBarController = window?.rootViewController as? UITabBarController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "NavController")
vc.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 1)
tabBarController.viewControllers?.append(vc)
}
Jede Zeile davon ist neu, also lass uns etwas tiefer graben:
rootViewController
-Eigenschaft gesetzt. Das wird alles vom Storyboard erledigt.ViewController
der Root View Controller, aber wir haben diesen in einen Navigation Controller eingebettet, und dann diesen in einen Tab Bar Controller eingebettet. Daher ist für uns der Root View Controller ein UITabBarController
.ViewController
händisch erzeugen, was bedeutet, zunächst eine Referenz auf unsere Datei Main.storyboard zu erhalten. Das geht mit Hilfe der Klasse UIStoryboard
, wie gezeigt. Du brauchst kein Paket ("Bundle") anzugeben, denn nil
heißt so viel wie "verwende das aktuelle App-Paket".instantiateViewController()
, in dem wir die Storyboard-ID des View Controllers übergeben, den wir haben wollen. Wir haben bereits unserem Navigation Controller die ID "NavController" gegeben, also übergeben wir diese.UITabBarItem
-Objekt für den neuen View Controller und geben ihm das Symbol "Top Rated" ("Am besten bewertet") und das Etikett ("Tag") 1. Dieses Etikett wird gleich noch wichtig werden.viewControllers
unseres Tab Bar Controllers hinzu, wodurch er in der Tab Bar auftauchen wird.Der Code erzeugt also einen duplizierten ViewController
, der in einem Navigation Controller verpackt ist, gibt ihm ein neues Tab Bar Item, um ihn vom existierenden Tab zu unterscheiden, und fügt ihn dann zur Liste sichtbarer Tabs hinzu. Das erlaubt uns, dieselbe Klasse für beide Tabs zu verwenden, ohne irgendetwas im Storyboard duplizieren zu müssen.
Der Grund, warum wir dem neuen UITabBarItem
das Etikett 1 gegeben haben, ist, dass dies eine einfache Methode zum Identifizieren ist. Wie du dich erinnerst, enthalten beide Tabs einen ViewController
, was bedeutet, dass der selbe Code ausgeführt wird. Hier bedeutet das, dass beide den gleichen JSON-Kanal runterladen werden, was die Benutzung von zwei Tabs sinnlos macht. Aber wenn du den String urlString
in der Methode viewDidLoad()
in ViewController.swift durch diesen hier ersetzt, wird es viel besser funktionieren:
let urlString: String
if navigationController?.tabBarItem.tag == 0 {
urlString = "https://api.whitehouse.gov/v1/petitions.json?limit=100"
} else {
urlString = "https://api.whitehouse.gov/v1/petitions.json?signatureCountFloor=10000&limit=100"
}
Damit wird der Code so angepasst, dass die erste Instanz von ViewController
die ursprüngliche JSON lädt, und die zweite nur Petitionen mit mindestens 10.000 Unterschriften.
Das Projekt ist beinahe fertig, aber wir machen noch eine letzte Änderung. Unser momentaner Code zum Laden ist nicht besonders widerstandsfähig: wir haben zwar ein paar if
-Ausdrücke, um zu prüfen, dass alles korrekt abläuft, aber keine else
-Ausdrücke, die Fehlermeldungen anzeigen, wenn es ein Problem gibt. Das erledigen wir einfach, indem wir eine neue Methode showError()
hinzufügen, die einen UIAlertController
erzeugt, der eine allgemeine Fehlermeldung anzeigt:
func showError() {
let ac = UIAlertController(title: "Loading error", message: "There was a problem loading the feed; please check your connection and try again.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
Du kannst nun den Code zum Runterladen und Parsen von JSON so anpassen, dass er diese Fehler-Methode aufruft, wann immer eine Bedingung fehlschlägt, so wie hier:
if let url = URL(string: urlString) {
if let data = try? Data(contentsOf: url) {
parse(json: data)
return
} else {
showError()
}
} else {
showError()
}
Alternativ könnten wir das auch noch ein bisschen mehr aufräumen, indem wir ein return
nach dem Aufruf von parse()
einfügen. Das bedeutet, dass die Methode beendet wird, nachdem das Parsen erreicht wurde, daher kommen wir nur ans Ende der Methode, wenn das Parsen nicht erreicht wurde und können den Fehler anzeigen. Probier also mal das hier:
if let url = URL(string: urlString) {
if let data = try? Data(contentsOf: url) {
parse(json: data)
return
}
}
showError()
Beide Vorgehensweisen sind vollkommen zulässig - nimm einfach die, die du bevorzugst.
Egal, für welche du dich entscheidest, die App zeigt nun Fehlermeldungen an, wenn es Probleme gibt, und wir sind fertig - gute Arbeit!
SPONSORED AppSweep by Guardsquare helps developers automate the mobile app security testing process with fast, free scans. By using AppSweep’s actionable recommendations, developers can improve the security posture of their apps in accordance with security standards like OWASP.
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.