Guard Statement

Introduction

Welcome to Lesson 3 of The Swift Fundamentals. When I started learning Swift for the first time, an else-if statement made sense. However, a guard statement rather seemed daunting. In fact, the name doesn’t tell anything about what it does. One day, however, I discovered something. A guard statement is just another for you to write an else-if statement. A guard statement promotes zenness. In other words, it adds clarity, emptiness, and lots of cloud and space. Let us find out through examples.

Zenness: A trait where peace, calmness, and inner awesomeness are all intertwined - Urban Dictionary

Problem

  1. Is there any alternative way to write an else-if statement?
  2. How do you safely unwrap multiple optionals?

Typical Else-If

Without having known about guard, you have used a long else-if statement to indicate an error message block.

  1. func checkDrinkingAge() {
  2. let canDrink = true
  3. if canDrink {
  4. print("You may enter")
  5. // More Code
  6. // More Code
  7. // More Code
  8. } else {
  9. // More Code
  10. // More Code
  11. // More Code
  12. print("Let me take you to the jail")
  13. }
  14. }

Issues with Else-If

  1. Nested brackets
  2. Have to read every line to spot the error message

Guard Statement

A guard block only runs if the condition is false, and it will exit out of the function through return. If the condition is true, Swift ignores the guard block. It provides an early exit and fewer brackets.

  1. func checkDrinkProgram() {
  2. let iCanDrink = true
  3. guard iCanDrink else {
  4. // if iCanDrink == false, run this block
  5. print("Let's me take you to the jail")
  6. return
  7. }
  8. print("You may drink")
  9. // You may move on
  10. // Come on.
  11. // You may leave
  12. // You don't need to read this.
  13. // Only one bracket on the bottom: feeling zen.
  14. }

Unwrap Optionals with Else-If

A guard statement is not only useful for replacing a typical conditional block with an else-if statement, but also great for unwrapping optionals by minimizing the number of brackets. To compare, let’s first begin how to unwrap multiple optionals with else-if.

First, let us create three optionals that will be unwrapped.

  1. var publicName: String? = "Bob Lee"
  2. var publicPhoto: String? = "Bob's Face"
  3. var publicAge: Int? = nil

The Worst Nightmare

You never want to do this.

  1. func unwrapOneByOne() {
  2. if let name = publicName {
  3. if let photo = publicPhoto {
  4. if let age = publicAge {
  5. print("Bob: \(name), \(photo), \(age)")
  6. } else {
  7. print("age is mising")
  8. }
  9. } else {
  10. print("photo is missing")
  11. }
  12. } else {
  13. print("name is missing")
  14. }
  15. }

The code above certainly works but violates the DRY principle. It’s atrocious. Let us break it down.

DRY: Don’t Repeat Yourself

Slightly Better

The code below is more readable than above.

  1. func unwrapBetter() {
  2. if let name = publicName {
  3. print("Yes name")
  4. } else {
  5. print("No name")
  6. return
  7. }
  8. if let photo = publicPhoto {
  9. print("Yes photo")
  10. } else {
  11. print("No photo")
  12. return
  13. }
  14. if let age = publicAge {
  15. print("Yes age")
  16. } else {
  17. print("No age")
  18. return
  19. }
  20. }

When Swift encounters return, it stops and exits out of the function immediately

Unwrap with Guard

The else-if statements can be replaced with guard.

  1. func unwrapOneByOneWithGuard() {
  2. guard let name = publicName else {
  3. print("Name missing")
  4. return
  5. }
  6. guard let photo = publicPhoto else {
  7. print("Photo missing")
  8. return
  9. }
  10. guard let age = publicAge else {
  11. print("Age missing")
  12. return
  13. }
  14. print(name)
  15. print(photo)
  16. print(age)
  17. }

Unwrap Multiple Optionals with Else-If

So far, you’ve been unwrapping optionals one by one. Swift allows us to unwrap multiple optionals at once. If one of them contains nil, it will execute the else block.

  1. func unwrap() {
  2. if let name = publicName, let photo = publicPhoto, let age = publicAge {
  3. print("Your name is \(name). I see your face right here, \(photo), you are \(age)")
  4. } else {
  5. // if any one of those is missing
  6. print("Something is missing")
  7. }
  8. }

Important: Be aware that when you unwrap multiple optionals at once, you can’t identify which contains nil.

Unwrap Multiple Optionals with Guard

Of course, we should use guard over else-if.

  1. func unwrapWithGuard() {
  2. guard let name = publicName, let photo = publicPhoto, let age = publicAge else {
  3. // if one or two of the variables contain "nil"
  4. print("Something is missing")
  5. return
  6. }
  7. print("Your name is \(name). I see your, \(photo). You are \(age).")
  8. // Animation Logic
  9. // Networking
  10. // More Code, but still zen
  11. }

Defer Statement

Defer Statement: Put off (an action or event) to a later time; postpone.

A defer block only executes only after current scope (loop, method, etc) exits.

  1. func simpleDefer() {
  2. defer { print("Chill, later") }
  3. print("Print First")
  4. }

Let us execute the simpleDefer() function.

  1. simpleDefer()
  2. // "Print First"
  3. // "Chill, later"

Another example,

  1. for i in 1...3 {
  2. defer { print ("Deferred \(i)") }
  3. print ("First \(i)")
  4. }
  5. // First 1
  6. // Deferred 1
  7. // First 2
  8. // Deferred 2
  9. // First 3
  10. // Deferred 3

Usage Case for Defer

  • Executing completion handler blocks which you will learn in Chapter 3.
  • Any code you want to explicitly inform your team without requiring them to read the entire function

Source Code

1003_guard_defer_statement.playground

Conclusion

In this lesson, you’ve learned the power of guard over typical else-if. First, it provides an early exit. Second, no one has to read the entire function to spot the error messages. You use a guard statement not just to please yourself, but for the sake of your teammates’ falling hair when he/she reads your code. Keep guarding, everyone. Don’t defer your learning, however.