History of the Question:
defer was introduced in Swift for better resource management and performing operations after the completion of a code block, similar to finally in other languages. This construct helps to explicitly show the stages of cleanup or finalization of work with resources.
Problem:
Many beginners believe that defer immediately executes the nested code, not always correctly understanding the timing of execution. There are also situations when multiple defer blocks can be hard to understand if one is not familiar with the LIFO (last-in, first-out) rule. Issues may arise with try/catch and early exits.
Solution:
defer executes the nested code at the very end of the scope, before exiting the current block of the function, even if the exit from the function occurs earlier (through return, throw, break, etc.). Multiple defer statements are executed in the reverse order of their appearance.
Code example:
func readFile() { print("Open file") defer { print("Close file") } print("Read line 1") if Bool.random() { print("Early return!") return } print("Read line 2") } readFile() // In the console, it will always show: Open file, ..., Close file (at the end)
Key features:
Can you use defer outside of a function?
No, defer is only allowed inside functions, methods, initializers, and deinitializers. It cannot be placed, for example, in the global scope of a file or inside code sources outside of functions.
What happens to defer if there is an exception (throw) in the block?
defer will still execute. This is one of its advantages — the resource is guaranteed to be released even in the case of an error (throw). This implements the safe resource release pattern.
In what order are multiple defer statements executed?
They are executed in reverse order (LIFO): the defer that was declared later will execute first.
Code example:
func test() { defer { print("First") } defer { print("Second") } print("Inside") } test() // Will output: "Inside", "Second", "First"
A function with several, non-sequentially placed defer statements; forgot to clean up some resources, returning from the function in different places. This leads to resource leaks and difficulty debugging behavior.
Pros: Uniformity of code, "gathered" cleanup actions in one place.
Cons: Hard to track what will execute and in what order; potential leaks due to logic errors.
One defer is created for each important stage, placed right where the resource is initialized, with comments. The code is checked in code review.
Pros: Guaranteed resource cleanup, clear understanding of action order.
Cons: Requires discipline and attention when adding new resources and cleanup blocks.