Lektion 1.9 · Stufe 1 – Swift-Fundament

Optionals II: if let, guard let, ??

ca. 15 Minuten Lesezeit

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:

Swift
let input = "42"
let number = Int(input)       // Int?
let doubled = number * 2      // ❌ Fehler

Du 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:

Swift
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:

Swift
let nickname: String? = "Annie"

if let nickname = nickname {
    print("Hallo, \(nickname)!")
}

Weil das so häufig ist, gibt es eine Kurzform:

Swift
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:

Swift
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:

Swift
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:

Swift
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:

Swift
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 mit return. 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:

Swift
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:

Swift
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:

Swift
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?

Swift
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:

Swift
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:

Swift
let friends: [String] = []
let initial = friends.first?.first
print(initial)   // nil, das Array ist leer

Lies das als: „Nimm den ersten Freund, falls es einen gibt, und davon den ersten Buchstaben.“

Optional Chaining kombiniert man oft mit ??:

Swift
let length = nickname?.count ?? 0

„Die Länge des Spitznamens, oder sonst 0.“

Alle vier im Überblick

Swift
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

Swift
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

Swift
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

Swift
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

Swift
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

Anfänger

Ü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!
Swift
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.

Fortgeschritten

Ü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!
Swift
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
Profi

Ü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!
Swift
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 let packt aus und verzweigt. Der Wert gilt nur im Block. Kurzform: if let name { ... }.
  • guard let packt 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 Ergebnis nil.
  • Mehrere Bedingungen in if let und guard let trennst du mit Kommas.
  • Alle vier Werkzeuge sind sicher. ! brauchst du nicht.

Spickzettel

Swift
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

Lektion geschafft?

Markiere sie als erledigt, damit du deinen Fortschritt siehst.