• 4 min reading time

18 Oct 2019

Never Forget to Update Your App UI Again

Control your flow using the Defer block in Swift


defer is a Swift statement explicitly designed to run an action just before exiting the current scope. It’s intended to be mainly used to update your UI or clean up after work has completed within the current block.


Image by Jamie Street


defer statements do come with some power, but might require some bending of your brain if you haven’t used them before. That was certainly the case for me, so I’ve decided to come up with three real app examples you can use in your codebase today. The main thing to wrap your head around, as the name defer suggests: the defer block will wait until the current execution block is completed, and fire immediately after.


In other words, you declare a defer block and instead of it running immediately, defer says “see you later,” and executes as soon as the current scope completes.


Typically, code executes from top to bottom, however that’s not the case for defer. No matter where within an execution block you put it, a defer block will run last.


There might also be a case where you use more than one defer in an execution block. In that case, the rule is: defer blocks execute in order from bottom to top. That means your bottommost defer runs first, and the topmost defer will run last.


There might also be a case where you use more than one defer in an execution block. In that case, the rule is: defer blocks execute in order from bottom to top. That means your bottommost defer runs first, and the topmost defer will run last.


That is not to be confused with the code that you put inside the defer block, as that executes in the usual top-to-bottom fashion. It’s only the block itself that waits for later execution.


Hopefully, that should make sense. Let’s have a look at three real app examples of using a defer block within production code.


Defer as a Convenience

Let’s imagine this situation: You’re working on a team of five developers, and you’re writing a complex function that handles processing a long string. Eventually at least two members will touch (or at least look up) the code within that function. You want to make sure that the UI gets updated upon function execution. You can use a defer block at the very top of your function to make sure that you update the UI as soon as that function finishes executing.

func getConsonants(from string: String) -> String {
    defer {
        // Update UI in here after the work has completed
        // i.e. you could change the background colour of a view to celebrate the occasion
        // view.backgroundColor = .yellow
        // or just print out a sun to the console
        print("🌞")
    }
    let vowels = CharacterSet(charactersIn: "aeiou")
    return string
        .components(separatedBy: vowels)
        .joined()
}

Using Multiple Defers

Sometimes you might want to defer more operations within the same execution block. In that case, you can use as many defer statements as you like consecutively. The rule again here is that topmost defer within the execution block will get executed last.

func add(firstValue: Int, secondValue: Int) -> Int {
    defer { // this executes last
        // you could fire a local notification here
        // or call into another function
    }
    
    defer { // this executes second
        print("Succesfully calculated the values")
    }

    return firstValue + secondValue // this executes first
}

Deferring an Operation

Imagine a situation when business logic dictates on every value lookup return current value ,and increases the value by one immediately after.


An example would be something like: return current page view count and increase it by one immediately after.

var value: Int = 0
var currentValue: Int {
    defer { value += 1 } // adds one immediately after returning
    return value // returns first
}

Conclusion

defer is a cool statement you can use while writing code in Swift; however, it’s to be used with a good measure. In many cases, such as an early returning guard statement, a do-catch block, or even a simple if statement, is enough to control flow and/or complete the execution.


defer statements shouldn’t necessarily be used on long execution blocks as they might confuse other programmers reading your code, or even you yourself after coming back to it at a later point. All that said, defer statements make an excellent use case for simple and readable code.


I hope you enjoyed this article and learned something new on the way.


If you have any thoughts on this article, I would love to hear them!
You can always get in touch with me via Twitter or LinkedIn 🙂


Cheers,


Tim