defer — was es ist, Syntax und Ausführungsreihenfolge

Autor: IT Sectr Veröffentlicht: 2026-06-20 Lesezeit: 8 Min.

defer ist eine Kontrollflusskonstruktion in Swift, die die Ausführung eines Codeblocks für den Zeitpunkt des Verlassens des aktuellen Gültigkeitsbereichs (Scope) plant. Der defer-Block wird unabhängig davon ausgeführt, wie der Scope endet — return, break, throw, fatalError oder normale Beendigung. Laut dem Swift Language Guide (2025) werden mehrere defers in einem Scope in umgekehrter Reihenfolge ihrer Deklaration ausgeführt — der zuletzt deklarierte wird zuerst ausgeführt (LIFO). Dies macht defer unverzichtbar für die garantierte Ressourcenbereinigung: Schließen von Dateideskriptoren, Freigeben von Sperren, Freigeben temporärer Zeiger, ohne das Risiko, die Bereinigung bei vorzeitigem Verlassen zu verpassen.

Wichtigste Punkte

  • defer — ein Codeblock, der beim Verlassen eines Scopes ausgeführt wird, unabhängig vom Grund des Verlassens (return, throw, break)
  • LIFO-Reihenfolge: mehrere defers werden von unten nach oben ausgeführt — der zuletzt deklarierte wird zuerst ausgeführt
  • Ressourcenbereinigung — Hauptanwendungsfall: Dateien schließen, Sperren freigeben, Animationen abschließen
  • Variablenauswertung: defer sieht Variablen zum Zeitpunkt des Verlassens, nicht zum Zeitpunkt der Deklaration
  • Ersetzt nicht do-catch zur Fehlerbehandlung — defer kümmert sich um die Bereinigung, nicht um die Flusskontrolle

Was ist defer?

defer ist eine Kontrollflusskonstruktion in Swift, eingeführt in Swift 2.0 (2015), die die Ausführung ihres Blocks verzögert, bis der aktuelle Scope beendet ist. Das Hauptmerkmal: defer garantiert, dass sein Rumpf unabhängig davon ausgeführt wird, wie der Scope endet — erfolgreich (return), mit einem Fehler (throw), vorzeitig (break, continue) oder fatal (fatalError, precondition).

Syntaktisch sieht defer wie defer { /* Code */ } aus und kann überall innerhalb eines Scopes platziert werden. Der Swift-Compiler garantiert, dass der Code innerhalb von defer ausgeführt wird, selbst wenn zwischen der defer-Deklaration und dem Ende des Scopes eine Ausnahme oder ein return auftritt. Dies unterscheidet defer grundlegend von normalem Code am Ende einer Funktion, der bei vorzeitigem Verlassen übersprungen werden kann.

Laut einem Artikel von Chris Lattner (Swift-Erfinder, 2015) wurde defer von ähnlichen Konstrukten in anderen Sprachen inspiriert — defer in Go, finally in Java/Python, scope guard in C++ — jedoch mit einem wichtigen Unterschied: In Swift wird defer am Ende des Scopes ausgeführt, nicht unmittelbar nach einem try-catch-Block. Dies bietet ein vorhersagbareres Verhalten für die Bereinigung in Funktionen mit mehreren Ausstiegspunkten.

Verwenden Sie defer für symmetrisches Ressourcenmanagement: Datei öffnen → defer { close }, Sperre erwerben → defer { unlock }. Dieses Muster garantiert, dass die Ressourcenfreigabe unter keinen Umständen vergessen wird.

Ausführungsreihenfolge mehrerer defers

Wenn mehrere defers im selben Scope deklariert werden, werden sie in umgekehrter Reihenfolge der Deklaration ausgeführt (LIFO — Last In, First Out). Das bedeutet, dass der zuletzt deklarierte defer zuerst und der erste zuletzt ausgeführt wird:

swift
func exampleDeferOrder() {
    defer { print("Erster defer") }
    defer { print("Zweiter defer") }
    defer { print("Dritter defer") }

    print("Funktionsrumpf")
}
// Ausgabe:
// Funktionsrumpf
// Dritter defer
// Zweiter defer
// Erster defer

Die LIFO-Reihenfolge ist wichtig für die korrekte Verwaltung verschachtelter Ressourcen. Wenn Datei A zuerst geöffnet wird, dann Datei B, müssen sie in umgekehrter Reihenfolge freigegeben werden: zuerst B, dann A. Mit defer geschieht dies automatisch — deklarieren Sie defer direkt nach dem Öffnen jeder Ressource, und die Bereinigungsreihenfolge ist korrekt, unabhängig von der Anzahl der Ausstiegspunkte in der Funktion.

Laut Swift by Sundell (2024) macht diese Funktion defer ideal für verschachtelte Sperren und Transaktionen: Sperre erwerben → defer { unlock } → nächste erwerben → defer { unlock }. LIFO garantiert, dass Sperren in umgekehrter Erwerbsreihenfolge freigegeben werden, was Deadlocks verhindert.

Defer zur Ressourcenbereinigung

Der Hauptanwendungsfall von defer ist die garantierte Ressourcenbereinigung. Betrachten wir die Arbeit mit dem Dateisystem. Das Öffnen einer Datei über FileHandle erfordert ein explizites Schließen — defer garantiert, dass close in jedem Szenario aufgerufen wird:

swift
func readFile(path: String) throws -> String {
    let handle = try FileHandle(forReadingFrom: URL(fileURLWithPath: path))
    defer { try? handle.close() }

    let data = try handle.readToEnd()
    guard let data else { throw FileError.empty() }

    return String(data: data, encoding: .utf8) ?? ""
    // handle.close() wird auch bei throw oder return aufgerufen
}

Ein weiteres typisches Szenario sind UI-Animationen mit einem Ladeflag. Vor dem Starten eines Ladevorgangs setzen Sie das Flag isLoading = true, und defer setzt es beim Verlassen der Funktion auf false zurück, unabhängig vom Erfolg oder Misserfolg der Anfrage. Dies verhindert, dass das Flag aufgrund eines nicht behandelten Fehlers auf true bleibt und die Oberfläche dauerhaft blockiert.

Laut dem Bitbucket Engineering Blog (2024) wird defer auch für das Profiling verwendet: Zeichnen Sie die Zeit am Anfang einer Funktion auf, und in defer — berechnen und geben Sie die Differenz aus. Dies liefert genaue Leistungsmessungen für alle Ausführungspfade, einschließlich fehlerhafter.

Defer und Fehlerbehandlung

defer arbeitet effektiv mit throws-Funktionen zusammen. Wenn eine Funktion in jeder Phase einen Fehler werfen kann, garantiert defer die Bereinigung ohne Codeverdopplung in jedem catch-Block oder guard-frühen Ausstieg:

swift
func processTransaction() throws {
    let db = try openDatabase()
    defer { closeDatabase(db) }

    let user = try fetchUser(from: db)
    defer { logAudit(user) }

    let result = try performPayment(user)
    sendNotification(result)
    // closeDatabase(db) und logAudit(user) werden aufgerufen
    // bei jedem throw oder return
}

Wichtig: defer wird vor der Übertragung der Kontrolle aus dem catch-Block ausgeführt, aber nach dem Auftreten des Fehlers. Wenn ein Fehler innerhalb von defer geworfen wird, erlaubt Swift die Verwendung von try nicht direkt innerhalb von defer — Sie benötigen try? oder try!. Laut Apple-Dokumentation erlaubt Swift nicht, dass ein Fehler aus defer entweicht, da dies die Garantie der Blockausführung verletzen würde.

Platzieren Sie defer unmittelbar nach der Ressourcenerfassung. Dies folgt dem Prinzip der Nähe: Der Leser sieht Erfassung und Freigabe nebeneinander, was die Codezuverlässigkeit verbessert und die Codeüberprüfung vereinfacht.

Gültigkeitsbereichsregeln

defer wird beim Verlassen des Scopes ausgeführt, in dem es deklariert ist. Wenn defer innerhalb eines do-Blocks deklariert ist, wird es beim Verlassen dieses Blocks ausgeführt, nicht der äußeren Funktion. Wenn innerhalb einer for-Schleife — bei jeder Iteration:

swift
func scopeExample() {
    print("start")
    do {
        defer { print("do-Block defer") }
        print("inside do")
    }
    // "do-Block defer" wird hier ausgegeben
    print("after do")
}
    // Ausgabe: start, inside do, do-Block defer, after do

for i in 1...3 {
    defer { print("end iteration \(i)") }
    print("iteration \(i)")
}
    // Ausgabe: iteration 1, end iteration 1, iteration 2, end iteration 2, ...

Von defer erfasste Variablen werden zum Zeitpunkt des Verlassens des Scopes gelesen, nicht zum Zeitpunkt der defer-Deklaration. Wenn eine Variable zwischen der defer-Deklaration und dem Ende des Scopes geändert wird, sieht defer den letzten Wert. Dies ist ein wichtiger Unterschied zu Closures, bei denen die Erfassung zum Zeitpunkt der Erstellung erfolgt. Seien Sie vorsichtig: Änderungen an einer Variable nach der Deklaration von defer beeinflussen dessen Ausführung.

Häufige Fehler mit defer

Der erste Fehler — Annahme einer anderen Ausführungsreihenfolge als LIFO. Wenn die Bereinigungsreihenfolge wichtig ist und defers in der falschen Reihenfolge deklariert werden, können Ressourcen unter Verletzung von Abhängigkeiten freigegeben werden. Lösung: Deklarieren Sie defer unmittelbar nach dem Erfassen jeder Ressource. Zweite Ressource geöffnet → defer { close second } bevor die erste geschlossen wird.

Der zweite Fehler — Verwendung von defer für Logik, die nichts mit der Bereinigung zu tun hat. defer ist für garantierte Bereinigung gedacht, nicht für die Hauptflusskontrolle. Wenn Code in defer den Rückgabewert beeinflusst, ist dies fast immer ein Fehler. defer kann den Rückgabewert einer Funktion nicht ändern (im Gegensatz zu Java finally, wo return in finally das ursprüngliche return überschreibt).

Der dritte Fehler — Werfen eines Fehlers aus defer. Swift verbietet try innerhalb von defer, wenn der Fehler nach außen propagieren könnte. Verwenden Sie try? oder try! für Operationen, die einen Fehler werfen könnten, oder packen Sie sie in eine separate Funktion ohne throws. Laut O’Reilly „Swift in Depth“ (2025) ist es eine gute Praxis, Bereinigungsfunktionen non-throwing zu machen oder Fehler innerhalb von defer zu behandeln.

Häufig gestellte Fragen

Was ist defer in Swift?

defer ist eine Swift-Konstruktion, die die Ausführung eines Blocks verzögert, bis der aktuelle Scope verlassen wird. Der Block wird immer ausgeführt — bei return, throw, break oder normaler Beendigung. Es wird zur garantierten Ressourcenbereinigung verwendet: Dateien schließen, Sperren freigeben.

In welcher Reihenfolge werden mehrere defers ausgeführt?

In umgekehrter Deklarationsreihenfolge (LIFO) — der zuletzt deklarierte defer wird zuerst ausgeführt. Dies garantiert eine korrekte Bereinigung verschachtelter Ressourcen: Wenn Ressource B nach A geöffnet wird, wird sie vor A geschlossen, was Abhängigkeiten von bereits freigegebenen Ressourcen verhindert.

Kann man einen Fehler aus defer werfen?

Nicht direkt — Swift verhindert die Fehlerausbreitung aus defer. Verwenden Sie try? oder try! für Operationen, die einen Fehler werfen könnten. Beste Praxis ist es, Bereinigungsfunktionen non-throwing zu machen oder Fehler innerhalb von defer zu behandeln, ohne sie nach außen zu propagieren.

Was ist der Unterschied zwischen defer und do-catch-finally?

defer ist an einen Scope gebunden und wird bei jedem Verlassen ausgeführt, einschließlich return, throw und break. finally (in anderen Sprachen) ist an try-catch gebunden und wird nur ausgeführt, wenn try vorhanden ist. Swift hat kein finally — defer deckt dieses Szenario vollständig ab und funktioniert für jeden Scope, nicht nur für die Fehlerbehandlung.

Sieht defer Variablenänderungen nach seiner Deklaration?

Ja, defer liest Variablen zum Zeitpunkt des Verlassens des Scopes, nicht zum Zeitpunkt der Deklaration. Wenn eine Variable nach der Deklaration von defer geändert wird, sieht der defer-Block den letzten Wert. Dies unterscheidet sich von normalen Closures, bei denen die Erfassung zum Zeitpunkt der Erstellung fixiert wird.

Zusammenfassung

  • defer — ein Finalisierungsblock, der beim Verlassen des Scopes unabhängig vom Grund ausgeführt wird (return, throw, break, normale Beendigung)
  • LIFO-Reihenfolge — mehrere defers werden von unten nach oben ausgeführt, der zuletzt deklarierte wird zuerst ausgeführt
  • Ressourcenbereinigung — Hauptanwendungsfall: Dateien schließen, Sperren freigeben, Zeiger freigeben, Animationen stoppen
  • Kompatibilität mit throws: defer wird nach einem Fehler, aber vor dem Verlassen des catch-Blocks ausgeführt; Fehler aus defer propagieren nicht
  • Scope: defer wird beim Verlassen des Scopes ausgeführt, in dem es deklariert wurde — do-Block, Schleife, Funktion
  • Variablenerfassung: defer liest Werte zum Zeitpunkt des Verlassens, nicht zum Zeitpunkt der Deklaration — achten Sie auf Änderungen
  • Beste Praxis: deklarieren Sie defer unmittelbar nach der Ressourcenerfassung, verwenden Sie defer nicht für Geschäftslogik, machen Sie Bereinigungsfunktionen non-throwing

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch