Introduced in Swift 2.0, The Swift defer statement isn’t something you’ll need to use often.
What is Defer?
A defer
statement is used for executing code just before transferring program control outside of the scope that the defer statement appears in. In simple words, defer is an operator used with closure where you include a piece of code that is supposed to be executed at the very end of the current scope.
Syntax
defer {
statements
}
Example
func f() {
defer { print("defer statement executed") }
print("End of function")
}
f()
// Prints "End of function"
// Prints "defer statement executed"
The above example defer
statement was executed after the print statement after the end of function f() ‘s Scope.
Multiple Defer
One of the most powerful features of defer
statement is that you can stack up multiple deferred pieces of work, and Swift will ensure they all get executed.
If you use multiple defer statements in the same scope, they’re executed in reverse order of appearance – like a stack, the order is LIFO(Last In First Out) or FILO(First In Last Out).
Example
func f() {
defer { print("First defer") }
defer { print("Second defer") }
print("End of function")
}
f()
// Prints "End of function"
// Prints "Second defer"
// Prints "First defer"
This reverse order is vital, ensuring everything in scope when a deferred block was created will still be in scope when the block is executed.
Not only does this mean you can defer work without having a worry about what if anything was already deferred, but also that Swift safely unwinds its defer stack based on the order you chose.
Defer does not capture value:
If a variable is referenced in the body of a defer
statement, its final value is evaluated. That is to say ‘Swift defer
statement do not capture the current state of a variable, and simply evaluate the value at the time it is run’.
func deferCapture() {
var a = "Hello! "
defer {print (a)}
a += "World"
}
deferCapture()
// Hello! World
So defer does not capture value, it will evaluate at the run time.
Break defer out of scope
The statements in the defer
statement can’t transfer program control outside of the defer statement. In simple words your defer calls shouldn’t try to exit the current scope using something like – return, throw, break, continue, etc.
What is the Use of defer Statement?
I hope you all understand how defer
statements work in different conditions, but questions arise what is the use of deferring in our project?
Although the defer keyword was already introduced in Swift 2.0, it’s still quite uncommon to use in projects. Its usage can be hard to understand, but using it can improve your code a lot in some places.
Make Sure Resource Cleared
Swift’s defer keyword lets us set up some work to be performed when the current scope exits. For Example, you might want to make sure that some temporary resources are cleaned up once a method exits, and defer will make sure that happens no matter how that exit happens.
Example
func writeLog() {
let file = openFile()
let hardwareStatus = fetchHardwareStatus()
guard hardwareStatus != "disaster" else { return }
file.write(hardwareStatus)
let softwareStatus = fetchSoftwareStatus()
guard softwareStatus != "disaster" else { return }
file.write(softwareStatus)
let networkStatus = fetchNetworkStatus()
guard neworkStatus != "disaster" else { return }
file.write(networkStatus)
closeFile(file)
}
Here some dummy Swift code that open file, write some data and close the file.
As you can see, a file is opened, then various types of data are written out before finally the file is closed.
But what happens if any one of those status checks returns “disaster”? Answer: our guard condition will trap the error and exit the method – leaving the file open.
There were two solutions to this, neither of which was nice. The first was to copy and paste the call to closeFile()
so that it is called before any of those returns
. The second was to create a pyramid of doom, with several stacked conditional statements to handle writing.
defer
statement will solve this problem, With that defer
call in place, closeFile()
will be called no matter which of the guards
are triggered, or even if none of them trigger and the method completes normally.
We could write the above code like this
func writeLog() {
let file = openFile()
defer { closeFile(file) }
let hardwareStatus = fetchHardwareStatus()
guard hardwareStatus != "disaster" else { return }
file.write(hardwareStatus)
let softwareStatus = fetchSoftwareStatus()
guard softwareStatus != "disaster" else { return }
file.write(softwareStatus)
let networkStatus = fetchNetworkStatus()
guard neworkStatus != "disaster" else { return }
file.write(networkStatus)
}
Consider using defer whenever an API requires calls to be balanced, such as allocate(capacity:) / deallocate(), wait() / signal(), or open() / close().
Ensuring results
Another usage of statement is by ensuring a result value to be returned in a completion callback. This can be very handy as it’s easy to forget to trigger this callback.
func getData(completion: (_ result: [String]) -> Void) {
var result: [String]?
defer {
guard let result = result else {
fatalError("We should always end with a result")
}
completion(result)
}
// Generate the result...
}
The statement makes sure to execute the completion handler at all times and verifies the result value, Whenever the result value is nil, the fatal error is thrown and the application fails.
Note:-In case of Multiple defer, Executing the last defer
statement in a given scope first means that statements inside that last defer
statement can refer to resources that will be cleaned up by other defer statements.
Conclusion :
Defer
is a useful tool in your programming armoury. You should be willing to use it, particularly when you think about cleaning up resources after you have completed some particular function.
Extend your knowledge
- Defer is listed in the Statements section of the Swift documentation (HERE)
The Twitter contact:
Any questions? You can get in touch with me here
[…] if you are an iOS Developer on wanna be an iOS Developer then maybe these articles will help defer statement, fallthrough statement, Access specifier in […]
[…] Note: please have a look at my latest post the defer statement. […]
[…] Defer Statement in Swift […]
[…] Defer Statement in Swift […]
[…] Defer Statement in Swift […]
[…] if you are an iOS Developer on wanna be an iOS Developer then maybe these articles will help defer statement, fallthrough statement, tableviews in […]
[…] Note: please have a look at my latest post the defer statement. […]
[…] Defer Statement in Swift […]
[…] Defer Statement in Swift […]