Guard Statement Explained In Swift

Written by Reinder de Vries on April 4 2019 in App Development

Guard Statement Explained In Swift

The guard statement in Swift helps you return your functions early, if a condition isn’t met. In this article we’ll discuss what guard is, and how you can use it in practical iOS development.

Here’s what we’ll get into:

  • How guard works and when it’s smart to use
  • How to unwrap optionals with guard let
  • Why it’s important to “early return” a function
  • Using guard in practical iOS development

Ready? Let’s get started!

  1. How To Use “guard” In Swift
  2. Early Returns – Why?
  3. Unwrapping Optionals With “guard let”
  4. Using “guard” In Practical iOS Development
  5. Further Reading

How To Use “guard” In Swift

You use the guard statement in Swift to (early) return a function when a condition isn’t met.

Let’s take a look at an example:

func sqrt(number: Int) -> Int?
{
    guard number >= 0 else {
        return nil
    }

    // Calculate and return square root of `number`
    return ...
}

In the above code, a hypothetical function sqrt(number:) calculates the square root of a given number and returns it. For example, the square root of 144 is 12, because 122 = 144.

You can’t calculate the square root of a negative number, so the sqrt(number:) function checks that number is greater than or equal to 0 by using the guard statement.

Here’s that guard statement once more:

guard number >= 0 else {
    return nil
}

It’s easiest to compare guard to a conditional, i.e. an if statement, that evaluates a logical expression.

In the above code, we’re checking if number >= 0. If it’s not, i.e. number is negative, the else clause of the guard block is invoked. This will return nil to the caller of the function, and the function exits.

It’s easiest to read the above code as: “Guard that number is greater than or equal to zero, or else, return nil.” See how that reads quite naturally?

If you look closely, you’ll notice that the guard statement is the opposite of an if statement. This doesn’t do guard justice, but it’s important to point out. Here, take a look at this:

if number < 0 {
    return nil
}

See how these guard and the if statements have the same effect? The else clause of the guard statement is invoked when number >= 0 evaluates to false.

The guard statement can only be used to “transfer program control out of scope”. This is a fancy way of saying that the body of the guard block, i.e. what’s inside the squiggly brackets, needs to exit the function.

You can do so with the following statements:

  • return, to exit a function or closure
  • break, to exit a loop like for
  • continue, to continue to the next loop iteration
  • throw, to exit a function and throw an error value

It’s worth noting here that you can’t only use guard in functions and closures, but also use it in loops like with for.

Here’s an example:

for i in 1...10 
{
    guard i.isMultiple(of: 2) else {
        continue
    }

    print(i)
}

In the above code we’re using the guard statement to check that an integer i is even, i.e. a multiple of 2. If it’s not, the continue statement causes the loop to continue to the next iteration.

Thanks to that bit of wizardry we can “guard” or “make sure” that a condition is met. And if it’s not, we can respond with exiting the scope.

†: In mathematics, no negative number can have a real square root.

Learn how to build iOS apps

Get started with iOS 12 and Swift 5

Sign up for our iOS development course Zero to App Store and learn how to build professional iOS 12 apps with Swift 5 and Xcode 10.

Early Returns – Why?

Is inverting if statements all there is to the guard statement? If it would be, we just might as well use if statements!

Here’s what the official Swift documentation says about guard:

A guard statement is used to transfer program control out of a scope if one or more conditions aren’t met.

What it means is that you use guard to exit a function (“transfer control out of scope”) when a condition isn’t met. For example, when the input for sqrt(number:) is negative.

If you already know that it doesn’t make sense to continue executing a function, you might as well exit the function early. This principle is called early return (or early escape or exit). It’s called “early” because you typically exit at the top of the function, when the computationally intense stuff hasn’t happened yet.

This is useful for a few reasons:

  • It’s clear: When a function returns early, and describes those early return conditions at the top of the function, you can quickly, clearly and comprehensively see the conditions in which a function won’t continue running.
  • It’s efficient: Why continue executing if the function isn’t going to complete anyway? It’s an efficient use of resources to escape the function as early as possible.

But… you could say the same about using if for an early return, right? What makes guard superior syntax for early returns?

  • It’s natural: The “Guard that [this] is true, or else…” syntax reads naturally in English, which makes it easier to comprehend what the code does.
  • It’s strict: You can only use guard to escape the scope (i.e., transfer program control out of scope) with return, break, etc. Making this explicit makes the control flow of your code clearer.
  • Motivates early returns: The explicit guard statement motivates developers to return a function early. Design choices that make coding safer and more productive can be seen throughout the Swift language.

The guard statement is technically only syntactic sugar, i.e. it merely sugarcoats already existing control flow mechanisms with more expressive syntax. This is a good thing – if it wouldn’t be, we would all still use punch cards…

Unwrapping Optionals With “guard let”

The guard statement has another use case. You can combine optional binding, i.e. if let, with guard.

Here’s an example:

func login()
{
    guard let username = usernameField?.text else {
        throw Error.invalidUsername
    }

    // Authenticate the user with `username`
    API.shared.login(username, ...)
}

In the above example we’re using guard let to do 3 things:

  1. Check that the expression usernameField?.text isn’t nil, i.e. unwrapping the optional
  2. If the expression isn’t nil, i.e. it has a value, we assign that value to the constant username
  3. If the expression is nil, the else clause of guard is invoked and an error is thrown, which exits the function

Let’s disect that statement for a bit. First, imagine your app attempts to authenticate a user with a username and a password. The view controller has a text field property called usernameField of type UITextField? (optional).

Both usernameField and its text property are optionals, so we’ll need to unwrap the optional to get to the value. A great approach is to use if let, like this:

if let username = usernameField?.text {
    // Do something with `username`
}

In the above code, we can safely use the username constant to authenticate the user. Thanks to if let we are 100% certain that the conditional body is only executed if usernameField?.text has a value.

Now, consider that we want to exit the function if usernameField?.text does not have a value – so when it’s nil. How can we do that?

Here’s one idea:

if let username = usernameField?.text {
    // Do something with `username`
} else {
    throw Error.invalidUsername
}

In the above code we’re throwing an error if usernameField?.text is nil, so we can respond to it having a value or it being nil.

This code has a few problems, though:

  • Late Return: In the spirit of early returns, the throwing code is now pushed lower into the function. The positive/valid code is at the top, and the negative/exit code is at the bottom. Imagine you have multiple conditions that check for validity. That can quickly turn into a pyramid of doom.
  • Verbose: We really just want to get the unwrapping out of the way as quickly as possible. The only thing we need is that username constant, and throwing an error if usernameField?.text is nil. We don’t need or want two conditional clauses for that!
  • Implicit: We’re not forced to throw or return in the else block; we’re not forced to transfer control out of scope. As a result, a careless developer might do poor man’s debugging with print() and not handle the error altogether. That’ll surely come back to bite you in the rear, later!

How do you solve this? Here’s how:

func login()
{
    guard let username = usernameField?.text else {
        throw Error.invalidUsername
    }

    // Authenticate the user with `username`
    API.shared.login(username, ...)
}

This guard let statement combines if let and guard. The usernameField?.text expression is tested for nil. If it’s nil, the error is thrown and the function exits. If it’s not nil, the value is assigned to username, and the function continues.

What’s counter-intuitive about guard let is that the username constant is available within the scope of the function, and not just the conditional body. You can use username “outside” of the squiggly brackets of guard let ... else { ... }.

Using “guard” In Practical iOS Development

If you’re already familiar with software development, you’re hopefully also familiar with the concept of early returns. It’s a good practice to exit a function or scope as soon as possible, if it becomes apparent that continuing execution makes no sense.

In practical iOS development, you’ll often see the guard statement as a one-liner. Here’s an example:

func parseAge(_ age: String)
{
    guard let age = Int(age) else { return }

    // Do something now that `age` is of type `Int`
}

In the above code, the failable initializer Int() is used to convert the string age to a constant with the same name of type Int. The guard statement is written on one line, which doesn’t affect its functionality (whitespace never does) and makes it much more pleasant to write.

Author’s Note: I recall a discussion on the Swift message boards about omitting the squiggly brackets, or even making else { return } implicit, but I can’t find it anymore… If doing so is useful, you can surely read about it on Swift Evolution.

Moving on. You’re likely to come across something like the following, in your iOS development work:

guard let username = usernameField?.text,
      let password = passwordField?.text, 
      !username.isEmpty, !password.isEmpty else {
    throw ...
}

See what’s happening there? The guard block is used to validate four conditions:

  1. If usernameField?.text is nil (unwrap and assign to username)
  2. If usernameField?.text is nil (unwrap and assign to password)
  3. If username is empty (i.e., string has zero length)
  4. If password is empty (i.e., string has zero length)

Just to be clear: it’s perfectly fine to check for these scenarios. It doesn’t make sense to attempt to authenticate the user if the password is empty or if the usernameField outlet property somehow is nil.

What’s annoying about this guard block, is that it can become unwieldy or unclear quickly. Just as with if let, it’s tempting to create a “pyramid of if let”, combining lots of conditionals and optional unwrapping, separated by commas.

Depending on your programming style, you can split up the above blocks in a few ways. First, it’s a good idea to separate the unwrapping with if let and the “simple” checks for isEmpty. Like this:

guard let username = usernameField?.text,
      let password = passwordField?.text {
    throw ...
}

if username.isEmpty || password.isEmpty {
    throw ...
}

In the above code, we’re even forgoing the guard statement in favor of a more descriptive if statement. It reads more naturally to say: “If username or password is empty”, compared to: “Guard that username not is empty, and password not is empty.” This is up for debate though. If you don’t agree, at least use it as an example to sharpen your thinking.

It’s also worth noting here that the use of a comma , is not exactly the same as && (logical AND). The effect of using a comma and using && is often similar, though. See SE-099.

Learn how to build iOS apps

Get started with iOS 12 and Swift 5

Sign up for our iOS development course Zero to App Store and learn how to build professional iOS 12 apps with Swift 5 and Xcode 10.

Further Reading

At first glance, the guard and guard let statements make your code easier to read, safer, and less error-prone. You can code more productively, knowing that guard statements check a condition and exit if it’s invalid.

If you look closer, you see the tension between designing a programming language that’s convenient for the developer without making it too strict and opinionated.

In any case, here’s what you learned:

  • How the guard statement works and when it’s best to use (for early returns)
  • Why early returns matter, because it’s efficient and increases clarity
  • How to unwrap optionals with guard let, and why that’s sometimes more convenient than if let
  • Using guard in practical iOS development – should you build a pyramid or not?

Want to learn more? Check out these resources:

Reinder de Vries

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.