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
- Is there any alternative way to write an
else-ifstatement? - 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
4. if canDrink {
5. print("You may enter")
6. // More Code
7. // More Code
8. // More Code
10. } else {
11. // More Code
12. // More Code
13. // More Code
14. print("Let me take you to the jail")
15. }
16. }
Issues with Else-If
- Nested brackets
- 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
4. guard iCanDrink else {
5. // if iCanDrink == false, run this block
6. print("Let's me take you to the jail")
7. return
8. }
10. print("You may drink")
11. // You may move on
12. // Come on.
13. // You may leave
14. // You don't need to read this.
15. // Only one bracket on the bottom: feeling zen.
16. }
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. }
9. if let photo = publicPhoto {
10. print("Yes photo")
11. } else {
12. print("No photo")
13. return
14. }
16. if let age = publicAge {
17. print("Yes age")
18. } else {
19. print("No age")
20. return
21. }
22. }
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. }
7. guard let photo = publicPhoto else {
8. print("Photo missing")
9. return
10. }
12. guard let age = publicAge else {
13. print("Age missing")
14. return
15. }
16. print(name)
17. print(photo)
18. print(age)
19. }
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
optionalsat once, you can’t identify which containsnil.
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. }
8. print("Your name is \(name). I see your, \(photo). You are \(age).")
9. // Animation Logic
10. // Networking
11. // More Code, but still zen
12. }
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. }
6. // First 1
7. // Deferred 1
8. // First 2
9. // Deferred 2
10. // First 3
11. // 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.
