Tutorial: JSON-Daten mit URLSession laden und mit SwiftUI anzeigen
Dieses Tutorial für zeigt Schritt für Schritt, wie JSON-Daten im Hintergrund mit der URLSession geladen werden, mit der JSONDecoder-Klasse dekodiert werden und mit SwiftUI zur Anzeige gebracht werden.
-
Dieses Tutorial setzt SwiftUI-Grundkenntnisse voraus. Sofern Du noch nicht mit SwiftUI gearbeitet hast, empfehle ich zuerst das SwiftUI Tutorial: Einführung in SwiftUI durchzuarbeiten.
-
Verwende für dieses Tutorial die aktuelle Version von Xcode (dieses Tutorial wurde zuletzt getestet am 15. Juli 2021 mit Xcode 12.5).
-
Erstelle ein neues App-Projekt Countries basierend auf SwiftUI.
-
Füge dem Projekt eine neue Swift-Datei mit einem Datentyp Country und einigen statischen Beispieldaten hinzu:
struct Country: Identifiable { var id: String var name: String static let allCountries = [ Country(id: "be", name: "Belgien"), Country(id: "bg", name: "Bulgarien"), Country(id: "el", name: "Griechenland"), Country(id: "lt", name: "Litauen"), Country(id: "pt", name: "Portugal"), ] }
-
Implementiere in ContentView mit einem ↗ List-View eine einfache tabellarische Darstellung der Länder:
struct CountriesView: View { var body: some View { List(Country.allCountries) { country in Text(country.name) } } }
-
Rufe im Browser die Beispiel-JSON-Daten auf und mache Dich mit dem Format der Daten vertraut:
-
Erstelle eine Klasse CountriesModel, die für das Laden und Halten der Daten zuständig ist. Lasse diese von ↗ ObservableObject erben und deklariere eine ↗ @Published-Eigenschaft countries. Dadurch wird das Objekt beobachtbar - wenn Sich die Liste der der Länder später ändert, kann das View reagieren:
class CountriesModel: ObservableObject { @Published var countries = Country.allCountries }
-
Verwende dieses Objekt für die Länderliste im View. Deklariere ein Property als ↗ @StateObject, damit SwiftUI die Instanz von dem Objekt verwaltet und bei Änderungen das Objekt automatisch aktualisiert:
struct CountriesView: View { @StateObject var countriesModel = CountriesModel() var body: some View { List( countriesModel.countries) { country in Text(country.name) } } }
-
Erstelle eine Methode reload im CountriesModel. Verwende den ↗ dataTask der ↗ URLSession um einen dataTask zu erzeugen und zu starten:
class CountriesModel: ObservableObject { @Published var countries = Country.allCountries func reload() { let url = URL(string: "https://www.ralfebert.de/examples/v2/countries.json")! let urlSession = URLSession.shared let task = urlSession.dataTask(with: url) { (data, response, error) in } task.resume() } }
Hinweis: Verwende die Code-Vervollständigung um den Aufruf zu tippen und achte darauf, die richtige Methode mit den Parametern URL und completionHandler auszuwählen:
Hinweis: Bestätige Sie den Xcode-Vorschlag mit Enter. Springe mit Tab zu dem completionHandler-Parameter und bestätige den Vorschlag ebenfalls mit Enter um den Block-Code zu erzeugen. Vergib hier die Variablennamen data, response, error für die Parameter:
-
Entferne in Countries.swift die Eigenschaft allCountries mit den Beispieldaten und deklariere den Typ als Codable:
struct Country : Identifiable, Codable { var id: String var name: String }
-
Passe die countries-Eigenschaft im CountriesModel so an, dass diese zunächst mit einer leeren Liste initialisiert wird:
class CountriesModel: ObservableObject { @Published var countries : [Country] = [] // ... }
-
Implementiere den completionHandler des dataTask: Verwende einen → JSONDecoder um die geladenen Daten zu dekodieren. Aktualisiere die Darstellung (dies muss auf dem → Main-Thread erfolgen, der completionHandler wird auf dem Hintergrund-Thread ausgeführt, der die Daten geladen hat):
let task = urlSession.dataTask(with: url) { (data, response, error) in // Error handling in case the data couldn't be loaded // For now, only display the error on the console guard let data = data else { debugPrint("Error loading \(url): \(String(describing: error))") return } // Parse JSON with JSONDecoder assuming valid JSON data let countries = try! JSONDecoder().decode([Country].self, from: data) // Update UI OperationQueue.main.addOperation { self.countries = countries } }
-
Füge im CountriesView einen onAppear-Block hinzu um das Laden der Daten auszulösen:
struct CountriesView: View { @StateObject var countriesModel = CountriesModel() var body: some View { List(countriesModel.countries) { country in Text(country.name) } .onAppear { self.countriesModel.reload() } } }
-
Starte die App mit Product » Run ⌘R und prüfe, dass die Länder geladen und angezeigt werden:
Weitere Informationen
-
JSON-Daten in SwiftÜberblick zum Handling von JSON-Daten in Swift.
-
URLSessionDokumentation zur URLSession-Klasse.