Swift Defer Statement
Execute cleanup code when leaving scope
โฐ What is Defer Statement?
Swift defer statements execute code just before leaving the current scope. They ensure cleanup tasks run regardless of how the function exits, making resource management safer and more reliable.
// Basic defer example
func processFile() {
print("Opening file...")
defer {
print("Closing file...")
}
print("Processing file...")
}
processFile()
Output:
Opening file...
Processing file...
Closing file...
Defer Statement Features
Cleanup Guarantee
Always executes before scope exit
defer {
cleanup() // Always runs
}
LIFO Order
Last defer executes first
defer { print("First") }
defer { print("Second") }
// Prints: Second, First
Resource Safety
Perfect for file/memory management
let file = openFile()
defer { file.close() }
Any Exit Path
Runs on return, throw, or natural exit
defer { cleanup() }
if error { return } // Still runs
๐น Defer Execution Order
Multiple defer statements execute in reverse order (LIFO):
func demonstrateOrder() {
print("Function starts")
defer {
print("Defer 1: This runs third")
}
print("Middle of function")
defer {
print("Defer 2: This runs second")
}
defer {
print("Defer 3: This runs first")
}
print("Function about to end")
}
demonstrateOrder()
Output:
Function starts
Middle of function
Function about to end
Defer 3: This runs first
Defer 2: This runs second
Defer 1: This runs third
๐น Resource Management Example
Perfect for ensuring resources are properly cleaned up:
func processDatabase() {
print("Connecting to database...")
defer {
print("Disconnecting from database...")
}
print("Starting transaction...")
defer {
print("Committing transaction...")
}
// Simulate some work
let success = true
if !success {
print("Error occurred!")
return // defer blocks still execute
}
print("Processing data...")
print("Work completed successfully")
}
processDatabase()
// File handling example
func readConfigFile() -> String? {
print("Opening config file...")
defer {
print("Closing config file...")
}
// Simulate file operations
let fileExists = true
guard fileExists else {
print("File not found!")
return nil // defer still runs
}
print("Reading file contents...")
return "config data"
}
let config = readConfigFile()
Output:
Connecting to database...
Starting transaction...
Processing data...
Work completed successfully
Committing transaction...
Disconnecting from database...
Opening config file...
Reading file contents...
Closing config file...
๐น Defer with Error Handling
Defer ensures cleanup even when errors are thrown:
enum FileError: Error {
case notFound
case corrupted
}
func processFileWithErrors() throws {
print("Starting file processing...")
defer {
print("Cleanup: Releasing resources...")
}
defer {
print("Cleanup: Clearing temporary data...")
}
// Simulate file operations
let fileExists = false
guard fileExists else {
print("File not found!")
throw FileError.notFound // defer blocks still execute
}
print("File processed successfully")
}
// Test error handling
do {
try processFileWithErrors()
} catch {
print("Caught error: \(error)")
}
// Defer in loops
func processItems() {
let items = ["item1", "item2", "item3"]
for item in items {
print("Processing \(item)...")
defer {
print("Finished processing \(item)")
}
// Simulate work
if item == "item2" {
print("Skipping \(item)")
continue // defer still runs for this iteration
}
print("Successfully processed \(item)")
}
}
Output:
Starting file processing...
File not found!
Cleanup: Clearing temporary data...
Cleanup: Releasing resources...
Caught error: notFound