What does the guard statement do?

I'm working on Apple's "Start Developing iOS Apps with Swift" tutorials. So far the code makes sense, except for line # 4 below where we are accessing UIImagePickerViewController to select an image from the user's photo library...


func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
     
     
      guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
         fatalError("Expected a Dictionary with an image, was provided: \(info)")
     
   }
      photoImageView.image = selectedImage
     
      dismiss(animated: true, completion: nil)
     
   }
   


What does guard statement do in general and what is it doing in this specific line of code?

Why and when should we use guard?

Answered by john daniel in 305233022

Hello mkhan094,

The general idea behind a guard statement is to be a "preflight" for the rest of your code. You could do if/then/else structures to do the same thing, but that adds complexity to your logic. If you are just checking for the validity of input statements, it is better to put that into a guard up-front and do an early return. You could use just an "if" statement that returns early. People have done that for years. The "guard" statement is just a formalization of the idea.


This specific guard statement is making sure that the info dictionary has a value for the "UIImagePickerControllerOriginalImage" and ensures that said value is a valid UIImage.


You use a guard to separate your low-level, error-handling boilerplate from your more important code logic.

Accepted Answer

Hello mkhan094,

The general idea behind a guard statement is to be a "preflight" for the rest of your code. You could do if/then/else structures to do the same thing, but that adds complexity to your logic. If you are just checking for the validity of input statements, it is better to put that into a guard up-front and do an early return. You could use just an "if" statement that returns early. People have done that for years. The "guard" statement is just a formalization of the idea.


This specific guard statement is making sure that the info dictionary has a value for the "UIImagePickerControllerOriginalImage" and ensures that said value is a valid UIImage.


You use a guard to separate your low-level, error-handling boilerplate from your more important code logic.

A 'guard' statement in general is an inverted 'if'. These two fragments do the same thing:


     if x != 0 { return false }


     guard x == 0 else { return false }


When you do optional binding, 'guard' and 'if' have slightly different effects:


     let y: Int? = // some optional value
     if let x = y { print ( x ) }
     print ( x ) // error: 'x' is not declared


     let y: Int? = // some optional value
     guard let x = y else { print ( x ) } // error: 'x' is not declared
     print ( x )


See the difference? With 'if', the variable 'x' is available inside the braces of the if statement. With 'guard', variable 'x' is available after the guard statement.


Guard has one additional requirement. The code inside the "else { … }" part must exit the enclosing scope. It is not allowed to fall through to the next line of code.


In your example:


      guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else { 
         fatalError("Expected a Dictionary with an image, was provided: \(info)") 
      }


this requirement is effectively met, because the compiler knows that 'fatalError' is one of those special functions that cannot return.

From the docs The Swift Programming Language (Swift 4.1): Control Flow

-=-

Early Exit

A guard statement, like an if statement, executes statements depending on the Boolean value of an expression. You use a guard statement to require that a condition must be true in order for the code after the guard statement to be executed. Unlike an if statement, a guard statement always has an else clause—the code inside the else clause is executed if the condition is not true.

func greet(person: [String: String]) {
    guard let name = person["name"] else {
        return
    }
   
    print("Hello \(name)!")
   
    guard let location = person["location"] else {
        print("I hope the weather is nice near you.")
        return
    }
   
    print("I hope the weather is nice in \(location).")
}

greet(person: ["name": "John"])
// Prints "Hello John!"
// Prints "I hope the weather is nice near you."
greet(person: ["name": "Jane", "location": "Cupertino"])
// Prints "Hello Jane!"
// Prints "I hope the weather is nice in Cupertino."


If the guard statement’s condition is met, code execution continues after the guard statement’s closing brace. Any variables or constants that were assigned values using an optional binding as part of the condition are available for the rest of the code block that the guard statement appears in.


If that condition is not met, the code inside the else branch is executed. That branch must transfer control to exit the code block in which the guard statement appears. It can do this with a control transfer statement such as return, break, continue, or throw, or it can call a function or method that doesn’t return, such as fatalError(_:file:line:).


Using a guard statement for requirements improves the readability of your code, compared to doing the same check with an if statement. It lets you write the code that’s typically executed without wrapping it in an else block, and it lets you keep the code that handles a violated requirement next to the requirement.

Thanks john daniel, QuinceyMorris, and KMT. All of your answers helped clear many questions I had about guard. This one particulary made the light bulb go off in the head "You use a guard statement to require that a condition must be true in order for the code after the guard statement to be executed."


Thanks!

What does the guard statement do?
 
 
Q