Asynchrone Programmierung in Swift: Ein vollständiger Praxisleitfaden
Asynchrone Programmierung ist eines der Schlüsselkonzepte der modernen iOS- und macOS-Entwicklung. In Swift wurde mit Version 5.5 das leistungsstarke System Structured Concurrency eingeführt, das die Arbeit mit Asynchronität einfach und sicher macht. In diesem Artikel behandeln wir die wichtigsten Werkzeuge: async/await, Task, Actor und Sendable, und zeigen deren Anwendung anhand realer Beispiele.
1. Grundlagen von async/await: Wie man aufhört, Closures zu schreiben und anfängt zu leben
Vor der Einführung von async/await wurde asynchroner Code in Swift mit Closures und Delegates geschrieben, was oft zur „Callback-Hölle“ führte. Der moderne Ansatz ermöglicht es, asynchronen Code genauso linear zu schreiben wie synchronen Code.
Eine asynchrone Funktion kann mit dem Schlüsselwort async deklariert werden. Der Aufruf einer solchen Funktion erfordert einen Kontext, der Asynchronität unterstützt, sowie das Schlüsselwort await.
// Beispiel einer asynchronen Funktion zum Laden von Datenfunc fetchUserData(userID: String) async throws -> User { let url = URL(string: "https://api.example.com/users/\\(userID)")! let (data, response) = try await URLSession.shared.data(from: url) guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { throw URLError(.badServerResponse) } let user = try JSONDecoder().decode(User.self, from: data) return user}
// VerwendungTask { do { let user = try await fetchUserData(userID: "123") print("User name: \\(user.name)") } catch { print("Error: \\(error)") }}Wichtige Merkmale:
async— Markierung einer asynchronen Funktionawait— Anhaltepunkt der Ausführung- Eine Funktion kann gleichzeitig
asyncundthrowssein - Der Thread wird nicht blockiert — während des Wartens kann er andere Arbeit erledigen
2. Task und TaskGroup: Verwaltung paralleler Aufgaben
Task ist die grundlegende Einheit asynchroner Arbeit. Sie erstellt eine neue asynchrone Aufgabe, die im globalen Thread-Pool ausgeführt wird. TaskGroup ermöglicht es, mehrere Aufgaben parallel zu starten und deren Ergebnisse zu sammeln.
Erstellen und Abbrechen von Tasks
// Erstellen einer Aufgabelet task = Task { let result = await performLongOperation() return result}
// Ergebnis abrufenlet value = await task.value
// Aufgabe abbrechentask.cancel()
// Prüfung auf Abbruch innerhalb der Aufgabefunc performLongOperation() async -> String { // Prüfen, ob die Aufgabe abgebrochen wurde guard !Task.isCancelled else { return "Cancelled" } // Lange Arbeit simulieren try? await Task.sleep(nanoseconds: 2_000_000_000) return "Completed"}Parallele Verarbeitung mit TaskGroup
// Paralleles Laden mehrerer Bilderfunc loadImages(urls: [URL]) async throws -> [UIImage] { return try await withThrowingTaskGroup(of: UIImage.self) { group in var images: [UIImage] = [] images.reserveCapacity(urls.count) for url in urls { group.addTask { let (data, _) = try await URLSession.shared.data(from: url) guard let image = UIImage(data: data) else { throw URLError(.cannotDecodeContentData) } return image } } // Ergebnisse sammeln, sobald sie bereit sind for try await image in group { images.append(image) } return images }}Wichtig: TaskGroup verwaltet automatisch den Lebenszyklus der untergeordneten Aufgaben