Der Operator defer verzögert die Ausführung von Code bis zum Verlassen des aktuellen Geltungsbereichs, normalerweise aus einer Funktion. Er ist nützlich für die Bereinigung von Ressourcen, das Schließen von Dateien und die Freigabe von Speicher – die sogenannte automatisierte Bereinigung.
Eigenschaften:
Beispiel:
func processFile() { let file = openFile() defer { closeFile(file) } // Arbeiten mit der Datei // Die Datei wird selbst im Falle von throw oder return geschlossen }
Ungewöhnliche Anwendungen: teilweise Imitation von 'finally'-Konstrukten, Gruppierung von Code für Logging und zur Verfolgung von Ausführungszeiten.
Wird defer ausgeführt, wenn die Anwendung während der Ausführung der Funktion beendet wird?
— Nein. Defer wird nur bei einem normalen Abschluss des Geltungsbereichs (return, throw oder normaler Ausgang) ausgeführt. Wenn die Anwendung unerwartet beendet wird (z. B. aufgrund des Signals SIGKILL oder fatalError), haben die Defer-Blöcke keine Zeit, ausgeführt zu werden.
Beispiel:
func foo() { defer { print("Cleanup") } fatalError("Crash!") // defer wird nicht ausgeführt }
Geschichte
Eine Funktion, die mit Sockets arbeitete, reinigte die Verbindung im Falle eines throw nicht. Daten blieben hängen, Verbindungen wurden nicht freigegeben. Nach der Einführung von defer funktionierte alles korrekt: Ressourcen wurden immer geschlossen.
Geschichte
Ein Entwickler versuchte, sich auf defer zur Freigabe eines globalen Zustands zu verlassen. Bei einem fatalError wurde die Ressource nicht freigegeben, was zu Blockierungen der Dienste und der Notwendigkeit eines Neustarts führte.
Geschichte
In einer Funktion wurden mehrere Defer-Deklarationen gemacht, in der Annahme, dass sie in der Reihenfolge ihrer Deklaration ausgeführt würden. Infolgedessen wurden Ressourcen in der falschen Reihenfolge geschlossen (z. B. wurde zuerst der Datei-Deskriptor geschlossen, und dann wurde versucht, darauf zuzugreifen). Lösung: sich an die LIFO-Reihenfolge der Ausführung von Defer-Blöcken erinnern.