EMZETT.
Login

Kurz: Seit Swift 5.5 gibt es strukturierte Nebenläufigkeit: Funktionen mit async können pausieren, await wartet auf ihr Ergebnis, ohne einen Thread zu blockieren.

Teil des Kurses Swift

Kapitel 6 von 8 im Kurs Swift (Abschnitt „Fortgeschritten“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

async/await

Seit Swift 5.5 gibt es strukturierte Nebenläufigkeit: Funktionen mit async können pausieren, await wartet auf ihr Ergebnis, ohne einen Thread zu blockieren.

import Foundation
 
func laden(_ id: Int) async -> String {
    try? await Task.sleep(nanoseconds: 50_000_000)       // simuliert Netzwerk
    return "Nutzer \(id)"
}
 
func laden(mitFehler: Bool) async throws -> Int {
    if mitFehler { throw URLError(.badURL) }
    return 42
}
 
let eins = await laden(1)
print(eins)
 
async let a = laden(2)                    // parallel starten
async let b = laden(3)
print(await a, await b)
 
let alle = await withTaskGroup(of: String.self) { gruppe in
    for id in 10...13 { gruppe.addTask { await laden(id) } }
    var ergebnisse: [String] = []
    for await r in gruppe { ergebnisse.append(r) }
    return ergebnisse.sorted()
}
print(alle)
 
do { print(try await laden(mitFehler: false)); print(try await laden(mitFehler: true)) }
catch { print("Fehler:", error is URLError) }
 
let task = Task { await laden(99) }
print(await task.value)

Ausgabe:

Nutzer 1
Nutzer 2 Nutzer 3
["Nutzer 10", "Nutzer 11", "Nutzer 12", "Nutzer 13"]
42
Fehler: true
Nutzer 99

Actors: sicherer gemeinsamer Zustand

Ein Actor schützt seinen Zustand: Nur ein Zugriff gleichzeitig, der Compiler erzwingt await.

actor Konto {
    private(set) var stand = 0
    func einzahlen(_ betrag: Int) { stand += betrag }
}
 
let konto = Konto()
await withTaskGroup(of: Void.self) { gruppe in
    for _ in 1...100 {
        gruppe.addTask { await konto.einzahlen(10) }
    }
}
print(await konto.stand)

Ausgabe:

1000

Apps mit SwiftUI

SwiftUI beschreibt Oberflächen deklarativ: Du sagst, wie die Ansicht zu einem Zustand aussieht, das Framework aktualisiert sie bei Änderungen.

import SwiftUI
 
struct ZaehlerView: View {
    @State private var anzahl = 0
 
    var body: some View {
        VStack(spacing: 16) {
            Text("Zähler: \(anzahl)")
                .font(.largeTitle)
            Button("Plus") { anzahl += 1 }
                .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}
 
@main
struct MeineApp: App {
    var body: some Scene {
        WindowGroup { ZaehlerView() }
    }
}
BausteinZweck
@Statelokaler Zustand einer Ansicht
@Bindinggeteilter Zustand mit einer Unteransicht
@Observable / ObservableObjectDatenmodell, das die Ansicht aktualisiert
List, NavigationStack, TabViewListen und Navigation
SwiftData, Core DataPersistenz
URLSessionNetzwerk

Daten laden und speichern (Codable)

import Foundation
 
struct Nutzer: Codable {
    let name: String
    let alter: Int
    let tags: [String]
}
 
let json = """
{"name": "Mia", "alter": 17, "tags": ["a", "b"]}
""".data(using: .utf8)!
 
let nutzer = try JSONDecoder().decode(Nutzer.self, from: json)
print(nutzer.name, nutzer.alter, nutzer.tags)
 
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys]
let ausgabe = try encoder.encode(Nutzer(name: "Tom", alter: 25, tags: []))
print(String(data: ausgabe, encoding: .utf8)!)
 
do {
    _ = try JSONDecoder().decode(Nutzer.self, from: "{}".data(using: .utf8)!)
} catch {
    print("Dekodierfehler:", error is DecodingError)
}

Ausgabe:

Mia 17 ["a", "b"]
{"alter":25,"name":"Tom","tags":[]}
Dekodierfehler: true

Ökosystem

  • Swift Package Manager: Package.swift, Pakete von GitHub (swift package init, swift build, swift test)
  • XCTest und Swift Testing (@Test) für Tests
  • Vapor und Hummingbird: Webserver in Swift
  • Swift on Server, Swift for Android, Embedded Swift
  • Apple-Frameworks: Foundation, SwiftUI, Combine, MapKit, CoreML, ARKit

Merke

  • async/await, async let, TaskGroup für nebenläufigen Code
  • actor schützt gemeinsamen Zustand
  • SwiftUI: deklarative Oberflächen mit @State, body, some View
  • Codable macht JSON einfach; Swift Package Manager für Abhängigkeiten

Übungsaufgabe

Lade mit async let drei simulierte Werte parallel und gib die Summe aus.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Protokolle, Generics, Extensions und Fehler

Weiter: Projekte: Praxisbeispiele

Alle Kapitel: Swift im Überblick