De defer-operator is geïntroduceerd in Swift voor veilige en gegarandeerde schoonmaak van middelen of het uitvoeren van code in een exit-blok van een zichtbaarheid, analoog aan finally/using/RAII in andere talen.
Meervoudige initialisatie, werken met bestanden, cross-scenario exits uit een functie — vereisen gegarandeerde vrijgave van middelen of uitvoering van logica (bestand sluiten, mutex ontgrendelen, object teruggeven aan pool, tijdelijke status resetten). Voordat defer bestond, moest alles handmatig worden gedaan bij elke return.
Defer garandeert de uitvoering van zijn code bij het verlaten van de huidige scope, ongeacht of de exit normaal was of via throw. Je kunt meerdere defer's declareren — ze worden in omgekeerde volgorde van declaratie uitgevoerd.
Voorbeeld van het vrijgeven van een hulpbron:
func processFile(path: String) throws { let file = try openFile(path) defer { file.close() } // Wordt gegarandeerd aangeroepen, zelfs bij fouten // ... werken met file ... }
Belangrijke kenmerken:
Kan defer variabelen per referentie vastleggen en hoe beïnvloedt dit het gedrag van closures?
Ja, defer legt alle gebruikte variabelen vast op het moment van aanroep, volgens de regels voor het vastleggen van closure (kopie voor waarde-type, referentie voor referentie-type). Het is een fout om een wijzigbare externe waarde-variabele vast te leggen — deze kan veranderen tegen de tijd dat defer wordt uitgevoerd.
Hoe werkt geneste defer binnen lussen en functies?
Als defer binnen een loop wordt gedeclareerd, wordt deze uitgevoerd bij elke voltooiing van de iteratie scope:
for _ in 1...3 { defer { print("Einde van iteratie") } print("Binnen") }
Geeft:
Binnen
Einde van iteratie
Binnen
Einde van iteratie
Binnen
Einde van iteratie
Kan defer niet uitgevoerd worden?
De uitvoering van de defer-code is alleen gegarandeerd als de scope daadwerkelijk wordt verlaten. Maar als het proces abrupt wordt beëindigd (fatalError, crash), of exit wordt aangeroepen, wordt defer niet uitgevoerd. Ook werkt defer niet op het niveau van objectmethoden — alleen binnen de scope van een functie/blok.
In de code na het openen van een bestand en het werken ermee, werd de return uitgevoerd door verschillende return/throw, en vergaten we op een gegeven moment het bestand te sluiten. Uiteindelijk lekte de open file handle naar het systeem.
Voordelen:
Nadelen:
Gebruik van defer voor gegarandeerde unlock van mutex, vrijgave van bestandshandle en reset van progress-vlag:
func criticalSection() { lock() defer { unlock() } // ... werken ... }
Voordelen:
Nadelen: