The defer statement postpones the execution of code until the current scope is exited, usually from a function. It is useful for resource cleanup, closing files, and freeing memory — so-called automated cleanup.
Features:
Example:
func processFile() { let file = openFile() defer { closeFile(file) } // Working with the file // file will be closed even in case of throw or return }
Unconventional use: partial imitation of constructs like 'finally', grouping code for logging and monitoring execution times.
Will defer execute if the application terminates during the execution of the function?
— No. Defer executes only on normal exit from the scope (return, throw or normal exit). If the application crashes (e.g., due to a SIGKILL signal or fatalError), the defer blocks will not be executed.
Example:
func foo() { defer { print("Clean up") } fatalError("Crash!") // defer will not execute }
Story
A function working with sockets did not clean up the connection in case of throw. Data remained hanging, connections were not released. After introducing defer, everything worked correctly: resources were always closed.
Story
A developer tried to rely on defer for releasing global state. When a fatalError occurred, the resource was not released, leading to service hangs and the need for a restart.
Story
In a function, several defer statements were declared, assuming they would execute in the order of declaration. As a result, resources were closed in the wrong order (for example, a file descriptor was closed first, and then access was attempted to it). Solution: remember the LIFO order of defer block execution.