SoFunction
Updated on 2025-04-11

Detailed explanation of several simple usage scenarios for defer in swift

Preface

Recently, I am going to scan the swift document again and found the keyword defer. Defer is a very important swift language feature. I am not stupid. I have never used this before. I will simply list the scenarios that can be used in this thing~~ I won’t say much, let’s take a look at the detailed introduction together.

What is defer used for

It's very simple. To summarize it in one sentence, the code in the defer block will be executed before the function returns, no matter which branch the function returns, there is a throw, or it will naturally go to the last line.

This keyword is the same as the try-catch-finally finally in Java. No matter which branch the try catch goes, it will be executed before the function return. And what's more powerful than Java's finally is that it can exist independently of try catch, so it can also become a small helper for organizing function processes. The processing you need to do anyway before returning the function can be put into this block to make the code look cleaner~

Here is an example from the swift documentation:

var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]
func fridgeContains(_ food: String) -> Bool {
 fridgeIsOpen = true
 defer {
  fridgeIsOpen = false
 }
 let result = (food)
 return result
}
fridgeContains("banana")
print(fridgeIsOpen)

The order of execution in this example is to first fridgeIsOpen = true , then the normal flow of the function body, and finally execute fridgeIsOpen = false before return .

Several simple usage scenarios

try catch structure

The most typical scenario, I think, is the main reason for the birth of the keyword defer:

func foo() {
 defer {
 print("finally")
 }
 do {
 throw NSError()
 print("impossible")
 } catch {
 print("handle error")
 }
}

Regardless of whether do block throw error, catch, or throw out, defer will be executed before the entire function return. In this example, print out "handle error" first and print out "finally".

You can also write defer in do block:

do {
 defer {
 print("finally")
 }
 throw NSError()
 print("impossible")
} catch {
 print("handle error")
}

Then the order of execution will be before the catch block, that is, print out "finally" and then print out "handle error".

Clean up and recycle resources

Similar to the example given in the swift document, a very suitable use scenario for defer is to do cleaning work. File operation is a good example:

Close the file

func foo() {
 let fileDescriptor = open(, O_EVTONLY)
 defer {
 close(fileDescriptor)
 }
 // use fileDescriptor...
}

In this way, you don’t have to worry about any branch forgetting to write it, or throwing an error in the middle, causing the fileDescriptor to not be closed normally. There are some similar scenarios:

dealloc space manually allocated

func foo() {
 let valuePointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
 defer {
 (capacity: 1)
 }
 // use pointer...
}

Add/Unlock: The following is a synchronized block similar to Objective-C in swift. You can use any NSObject as lock

func foo() {
 objc_sync_enter(lock)
 defer { 
 objc_sync_exit(lock)
 }
 // do something...
}

For pair-invoked methods like this, you can use defer to put them together for a glance.

Adjust completion block

This is a scenario that makes me feel that "if you knew defer" would be great. Sometimes there are many branches of a function, and maybe a small branch returned to forget to tune the completion block, and the result is a bug that is not easy to find. Use defer to avoid worrying about this problem:

func foo(completion: () -> Void) {
 defer {
  = false
 completion()
 }
 guard error == nil else { return } 
 // handle success
}

Sometimes completion has to pass different parameters according to the situation, and defer is not good at this time. However, if the completion block is saved, we can still use it to ensure that it can be released after execution:

func foo() {
 defer {
  = nil
 }
 if (succeed) {
 (.success(result))
 } else {
 (.error(error))
 }
}

Adjust super method

Sometimes, override method has the main purpose of making some preparations before the super method, such as prepare(forCollectionViewUpdates:) of UICollectionViewLayout, so we can put the part that calls super in defer:

func override foo() {
 defer {
 ()
 }
 // some preparation before ()...
}

Some details

Any scope can have defer

Although most usage scenarios are in functions, in theory, defer can be written between any { }. For example, a normal loop:

var sumOfOdd = 0
for i in 0...10 {
 defer {
 print("Look! It's \(i)")
 }
 if i % 2 == 0 {
 continue
 }
 sumOfOdd += i
}

Neither continue nor break will hinder the execution of defer. Even a defer can be written in a closure for no reason:

{
 defer { print("bye!") }
 print("hello!")
}

It doesn't make any sense...

Defer must be executed before it will be triggered
Suppose there is a question: Can defers in a scope be guaranteed to be executed? The answer is...for example:

func foo() throws {
 do {
 throw NSError()
 print("impossible")
 }
 defer {
 print("finally")
 }
}
try?foo()

No defer is executed, no print anything. This story tells us that at least we have to execute the defer line, it is guaranteed to trigger later. By the same token, it is also not possible to return in advance:

func foo() {
 guard false else { return }
 defer {
 print("finally")
 }
}

Multiple defers

A scope can have multiple defers, in the order of execution is like a stack: every time a defer is encountered, it is like pushing into a stack, and when the scope ends, the later stack is executed first. As in the following code, it will print it in the order of 1, 2, 3, 4, 5, and 6.

func foo() {
 print("1")
 defer {
 print("6")
 }
 print("2")
 defer {
 print("5")
 }
 print("3")
 defer {
 print("4")
 }
}

But I strongly recommend not writing this way. I suggest not having multiple defers in a scope, it feels like there is no benefit other than making the code-reader feel confused.

Summarize

The above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.