Skip to main content

What is the defer statement and what is the use of defer statement?

Defer Statement:

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

  1. defer {
  2. statements
  3. }

Example

  1. func f() {
  2. defer { print("defer statement executed") }
  3. print("End of function")
  4. }
  5. f()
  1. // Prints "End of function"
  2. // 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

  1. func f() {
  2. defer { print("First defer") }
  3. defer { print("Second defer") }
  4. print("End of function")
  5. }
  6. f()
  7. // Prints "End of function"
  8. // Prints "Second defer"
  9. // 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'.

  1. func deferCapture() {

        var a = "Hello! "

        defer {print (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

Here some dummy Swift code that open file, write some data and close the file.

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)

}


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 armory. You should be willing to use it, particularly when you think about cleaning up resources after you have completed some particular function.


Comments

Popular posts from this blog

Static Library, Dynamic Library, Framework Which is best way to distribute Custom Code?

If you’ve been developing for iOS for some time, you probably have a decent set of your own classes and utility functions that you reuse in most of your projects and shared with teams.  Well, there are different ways, the easiest way to reuse code is simply to copy/paste the source files. However,  this can quickly become a maintenance nightmare. Whenever you update the source code, you have to update the changes to all the files between teams and projects, Since each app gets its own copy of the shared code, it’s difficult to keep all the copies in synch for bug-fixes and updates. Also, this will not work if you don't want to expose the implementation details. When developing iOS apps you rarely implement everything from the ground-up, because operating systems, as well as the open-source community, offer a large amount of functionality ready-to-use. Such pieces of functionality are usually packed in a distributable form known as the library. In this article let's explore sta...

Which is the best way to distribute Custom Framework?

So You have a solution to a problem that many other iOS developers have and you want to help them, but you also want to protect your code and build a business? Binary Framework. That's what you want! You might have noticed that you can't see the source code of UIKit Framework you use to build your iOS apps on top of every day. That's because Apple ships the UIKit as a binary framework in its iOS SDK. Below are the available ways of creating Libraries or framework:-  Umbrella Framework:   In the Apple development environment, the  incorporation  of one framework into another is called “ Umbrella ”. This type of framework is meant to hide the use of some sub-frameworks and thus facilitate their use.   Umbrella frameworks available for macOS apps , but Apple does not recommend using them. Apple does not officially support the Umbrella Frameworks for  iOS,watchOS, or tvOS , indeed citing the official documentation: Don't create Umbrella Frameworks. While it is...