Lernziel
Nach dieser Lektion kannst du Optionals sicher auspacken: mit if let, guard let, dem Nil-Coalescing-Operator ?? und Optional Chaining ?.. Und du weißt, wann du welches Werkzeug einsetzt.
Das Problem: Der Wert steckt in der Verpackung
Aus der letzten Lektion weißt du: Ein Optional ist wie ein Geschenk, von dem du nicht weißt, ob etwas drin ist. Swift lässt dich den Inhalt erst benutzen, wenn du nachgeschaut hast:
let input = "42"
let number = Int(input) // Int?
let doubled = number * 2 // ❌ FehlerDu brauchst einen Weg, der sagt: „Falls ein Wert drin ist, gib ihn mir als ganz normalen Int. Falls nicht, mach etwas anderes.“ Swift bietet dafür vier Werkzeuge. Alle vier sind sicher. Keines stürzt jemals ab.
Werkzeug 1: if let
Das wichtigste Werkzeug:
let input = "42"
if let number = Int(input) {
print("Das Doppelte ist \(number * 2).")
} else {
print("\(input) ist keine Zahl.")
}So liest du das: „Wenn sich aus Int(input) ein Wert holen lässt, nenne ihn number und führe den Block aus. Sonst führe den else-Block aus.“
Innerhalb des ersten Blocks ist number ein ganz normaler Int, ohne Fragezeichen. Du kannst damit rechnen, wie du willst.
Erwartetes Ergebnis
Mit "42" steht in der Konsole: Das Doppelte ist 84.
Mit "Hallo" steht dort: Hallo ist keine Zahl.
Die Kurzform
Oft hat das Optional schon einen guten Namen, und du willst den ausgepackten Wert genauso nennen:
let nickname: String? = "Annie"
if let nickname = nickname {
print("Hallo, \(nickname)!")
}Weil das so häufig ist, gibt es eine Kurzform:
if let nickname {
print("Hallo, \(nickname)!")
}Beide Varianten machen genau dasselbe. Innerhalb des Blocks ist nickname ein String, außerhalb bleibt es ein String?.
Mehrere Optionals auf einmal
Brauchst du mehrere Werte, trennst du sie mit Kommas. Der Block läuft nur, wenn alle einen Wert haben:
let widthText = "8"
let heightText = "5"
if let width = Int(widthText), let height = Int(heightText) {
print("Fläche: \(width * height)")
}Du kannst sogar normale Bedingungen anhängen:
if let age = Int("17"), age >= 18 {
print("Volljährig")
}Werkzeug 2: guard let
if let ist großartig, hat aber einen Nachteil: Der ausgepackte Wert existiert nur innerhalb des Blocks. Prüfst du mehrere Dinge nacheinander, wandert dein Code immer weiter nach rechts:
if let name = nameInput {
if let age = Int(ageInput) {
if age >= 18 {
print("\(name) darf rein.")
}
}
}Diese Treppe nennen Programmierer scherzhaft Pyramide des Verderbens. guard let dreht die Logik um:
guard let number = Int(input) else {
print("Keine Zahl.")
return
}
print("Das Doppelte ist \(number * 2).")So liest du das: „Stell sicher, dass sich ein Wert holen lässt. Sonst brich hier ab.“
Zwei Dinge sind anders als bei if let:
- Der
else-Block muss den aktuellen Code verlassen, meist mitreturn. Swift prüft das und meldet einen Fehler, wenn du es vergisst. - Der ausgepackte Wert ist danach verfügbar, im ganzen restlichen Code.
guard und return
return heißt „verlasse diese Funktion“. Was Funktionen sind, lernst du in der nächsten Lektion. Deshalb funktioniert guard mit return im Playground nicht direkt auf oberster Ebene, sondern nur innerhalb einer Funktion. Merk dir das Muster jetzt und probier es in Lektion 1.10 aus.
guard eignet sich perfekt für den Anfang einer Funktion. Erst prüfst du alles, was nötig ist, und dann folgt der eigentliche Code, ohne Einrückung, ohne Pyramide:
func checkEntry(nameInput: String?, ageInput: String) {
guard let name = nameInput else {
print("Name fehlt.")
return
}
guard let age = Int(ageInput), age >= 18 else {
print("Nicht volljährig oder kein gültiges Alter.")
return
}
print("\(name) (\(age)) darf rein.")
}if let oder guard let?
if let, wenn du den Wert nur kurz brauchst und es in beiden Fällen sinnvoll weitergeht.guard let, wenn ohne den Wert nichts mehr Sinn ergibt. Frühes Aussteigen hält den restlichen Code flach und lesbar.
Werkzeug 3: ??, der Ersatzwert
Oft willst du gar nicht verzweigen. Du willst einfach einen Standardwert, falls nichts da ist:
let nickname: String? = nil
let displayName = nickname ?? "Gast"
print("Hallo, \(displayName)!") // Hallo, Gast!?? heißt Nil-Coalescing-Operator. Lies ihn als „oder sonst“: „Nimm den Spitznamen, oder sonst "Gast".“ Das Ergebnis ist kein Optional mehr.
Das ist dasselbe wie das default: beim Dictionary aus Lektion 1.7, nur für alle Optionals:
let ages = ["Anna": 34]
let bensAge = ages["Ben"] ?? 0
let count = Int("abc") ?? 0
let first = ["x", "y"].first ?? "leer"Und erinnerst du dich an die Motivations-App aus Lektion 0.4?
currentQuote = quotes.randomElement() ?? ""randomElement() liefert ein Optional, weil die Liste leer sein könnte. ?? "" sorgt dafür, dass im Notfall ein leerer Text verwendet wird. Jetzt verstehst du diese Zeile vollständig.
Achtung
Der Ersatzwert muss sinnvoll sein. age ?? 0 kann bedeuten, dass ein fehlendes Alter plötzlich als „null Jahre“ in eine Statistik eingeht. Frag dich immer: Ist der Ersatzwert wirklich richtig, oder brauche ich doch if let?
Werkzeug 4: Optional Chaining mit ?.
Manchmal willst du eine Eigenschaft oder Funktion eines Optionals benutzen:
let nickname: String? = "Annie"
let shout = nickname?.uppercased()
print(shout) // Optional("ANNIE")Das ?. heißt: „Falls ein Wert da ist, ruf uppercased() auf. Falls nicht, ist das ganze Ergebnis nil.“ Das Ergebnis ist deshalb wieder ein Optional.
Den Namen hat das Werkzeug, weil man mehrere solche Schritte zu einer Kette verbinden kann. Bricht ein Glied, ist das Ergebnis nil:
let friends: [String] = []
let initial = friends.first?.first
print(initial) // nil, das Array ist leerLies das als: „Nimm den ersten Freund, falls es einen gibt, und davon den ersten Buchstaben.“
Optional Chaining kombiniert man oft mit ??:
let length = nickname?.count ?? 0„Die Länge des Spitznamens, oder sonst 0.“
Alle vier im Überblick
let input: String? = readUserInput() // irgendein Optional
// 1. if let: verzweigen
if let input {
print("Eingabe: \(input)")
} else {
print("Keine Eingabe")
}
// 2. guard let: früh aussteigen (in Funktionen)
guard let input else { return }
// 3. ??: Ersatzwert
let text = input ?? "leer"
// 4. ?.: weitermachen, falls vorhanden
let upper = input?.uppercased()readUserInput() steht hier nur als Platzhalter für eine Stelle, an der ein Optional entsteht.
Typische Fehler
Ausgepackter Wert außerhalb von if let
if let number = Int("42") {
print(number)
}
print(number)Fehlermeldung
Cannot find 'number' in scope
Bei if let existiert der Wert nur im Block. Brauchst du ihn danach, nimm guard let.
guard ohne Ausstieg
guard let number = Int(input) else {
print("Keine Zahl")
}Fehlermeldung
'guard' body must not fall through, consider using a 'return' or 'throw' to exit the scope
Der else-Block von guard muss den aktuellen Bereich verlassen, z. B. mit return.
if let mit einem normalen Wert
let name = "Anna"
if let name {
print(name)
}Fehlermeldung
Initializer for conditional binding must have Optional type, not 'String'
name ist gar kein Optional, es gibt nichts auszupacken. Lass if let einfach weg.
Ersatzwert vom falschen Typ
let count = Int("abc") ?? "keine"Fehlermeldung
Binary operator '??' cannot be applied to operands of type 'Int?' and 'String'
Der Ersatzwert muss denselben Typ haben wie der Inhalt des Optionals, hier also Int.
FAQ
Anfänger
Was bedeutet das überhaupt?Welches Werkzeug soll ich am Anfang nehmen?
if let und ?? decken die meisten Fälle ab. guard let kommt dazu, sobald du Funktionen schreibst. Und ?. lernst du ganz nebenbei, wenn du es brauchst.
Warum kann ich nicht einfach ! nehmen? Ist doch kürzer.
Weil es abstürzt, wenn nil drin ist. Und irgendwann ist nil drin, oft erst bei einem Nutzer, nie bei dir beim Testen. Alle vier Werkzeuge aus dieser Lektion sind sicher.
Darf der ausgepackte Wert anders heißen als das Optional?
Ja: if let age = ageInput. Wenn das Optional schon einen guten Namen hat, nimm aber die Kurzform if let ageInput.
Fortgeschritten
Warum verhält es sich so?Kann ich mit if var auspacken, um den Wert zu ändern?
Ja. if var name { name += "!" } gibt dir eine veränderbare Kopie. Das Original-Optional bleibt aber unverändert.
Kann ich ?? verketten?
Ja: let name = nickname ?? fullName ?? "Gast". Swift nimmt den ersten Wert, der nicht nil ist.
Wo begegnen mir Optionals in SwiftUI?
Überall dort, wo Daten fehlen können: eine Auswahl in einer Liste (nichts ausgewählt), ein geladenes Bild (noch nicht da), ein Suchergebnis. In SwiftUI schreibst du dann z. B. if let selectedItem { DetailView(item: selectedItem) } direkt in body.
Profi
Was passiert unter der Haube?Wie funktioniert ?? so, dass die rechte Seite nur bei Bedarf ausgewertet wird?
Die rechte Seite ist als @autoclosure deklariert. Der Ausdruck wird automatisch in eine Closure verpackt und nur aufgerufen, wenn links nil steht. So kann rechts auch eine teure Berechnung stehen, ohne dass sie unnötig läuft. Closures lernst du in Lektion 1.11.
Was ist map auf einem Optional?
nickname.map { $0.uppercased() } macht dasselbe wie nickname?.uppercased(): Die Funktion wird nur angewendet, wenn ein Wert da ist. Mit map und flatMap lassen sich auch Umwandlungen ausdrücken, für die es keine Eigenschaft gibt, etwa ageText.flatMap { Int($0) }.
Übungen
Übung 1: Begrüßung
Leg ein Optional userName: String? an. Gib „Willkommen zurück, …!“ aus, wenn ein Name da ist, sonst „Willkommen, Gast!“. Löse die Aufgabe zweimal: einmal mit if let, einmal mit ??.
Lösung Übung 1Erst selbst probieren!
let userName: String? = "Anna"
// mit if let
if let userName {
print("Willkommen zurück, \(userName)!")
} else {
print("Willkommen, Gast!")
}
// mit ??
print("Willkommen, \(userName ?? "Gast")!")Die beiden Varianten unterscheiden sich leicht: Nur die if let-Version sagt „zurück“. Brauchst du in beiden Fällen unterschiedliche Texte, ist if let die richtige Wahl.
Übung 2: Summe der Eingaben
Gegeben ist let inputs = ["4", "acht", "15", "", "23"]. Berechne die Summe aller gültigen Zahlen und zähle, wie viele Eingaben ungültig waren.
Lösung Übung 2Erst selbst probieren!
let inputs = ["4", "acht", "15", "", "23"]
var sum = 0
var invalid = 0
for input in inputs {
if let number = Int(input) {
sum += number
} else {
invalid += 1
}
}
print("Summe: \(sum), ungültig: \(invalid)") // Summe: 42, ungültig: 2Übung 3: Lagerbestand
Ein Lager ist ein Dictionary: let stock = ["Äpfel": 12, "Birnen": 0, "Kiwis": 5]. Gib für eine Liste von Bestellungen ["Äpfel", "Bananen", "Birnen"] jeweils aus: „Äpfel: 12 auf Lager“, „Bananen: nicht im Sortiment“ oder „Birnen: ausverkauft“. Achte darauf, „nicht im Sortiment“ und „ausverkauft“ sauber zu unterscheiden. Warum wäre stock[item] ?? 0 hier ein Fehler?
Lösung Übung 3Erst selbst probieren!
let stock = ["Äpfel": 12, "Birnen": 0, "Kiwis": 5]
let orders = ["Äpfel", "Bananen", "Birnen"]
for item in orders {
if let amount = stock[item] {
if amount > 0 {
print("\(item): \(amount) auf Lager")
} else {
print("\(item): ausverkauft")
}
} else {
print("\(item): nicht im Sortiment")
}
}Mit stock[item] ?? 0 würden Bananen als „ausverkauft“ erscheinen. Der Ersatzwert würde zwei unterschiedliche Situationen vermischen. Genau davor warnt der Hinweis in dieser Lektion.
Zusammenfassung
if letpackt aus und verzweigt. Der Wert gilt nur im Block. Kurzform:if let name { ... }.guard letpackt aus oder steigt früh aus. Der Wert gilt danach. Ideal am Anfang von Funktionen.??liefert einen Ersatzwert:name ?? "Gast".?.greift nur zu, wenn ein Wert da ist, sonst ist das Ergebnisnil.- Mehrere Bedingungen in
if letundguard lettrennst du mit Kommas. - Alle vier Werkzeuge sind sicher.
!brauchst du nicht.
Spickzettel
if let value { ... } else { ... }
if let a = Int(x), let b = Int(y), a < b { ... }
guard let value else { return }
let name = optional ?? "Standard"
let upper = optional?.uppercased()
let length = optional?.count ?? 0