Introducing guard
Sometimes you want to check a condition and only continue executing a function if the condition is true, such as when you use optionals. Imagine a function that fetches some data from the network; that fetch might fail if the network is down. The usual way to encapsulate this behavior is using an optional, which has a value if the fetch succeeds, and nil otherwise.
Swift has a useful and powerful feature to help in situations like this: the guard statement.
Consider the following function:
func calculateNumberOfSides(shape: String) -> Int? { switch shape {
case "Triangle": return 3
case "Square": return 4
case "Rectangle": return 4
case "Pentagon": return 5
case "Hexagon":
return 6 default:
return nil
}
}
This function takes a shape name and returns the number of sides that shape has. If the shape isn’t known, or you pass something that isn’t a shape, then it returns nil.
You could use this function like so:
func maybePrintSides(shape: String) {
let sides = calculateNumberOfSides(shape: shape)
if let sides = sides {
print("A (shape) has (sides) sides.")
} else {
print("I don't know the number of sides for (shape).")
}
}
There’s nothing wrong with this, and it would work. However the same logic could be written with a guard statement like so:
func maybePrintSides(shape: String) {
guard let sides = calculateNumberOfSides(shape: shape) else { print("I don't know the number of sides for (shape).") return
}
print("A (shape) has (sides) sides.")
}
The guard statement comprises guard followed by a condition that can include both Boolean expressions and optional bindings, followed by else, followed by a block of code. The block of code covered by the else will execute if the condition is false.
The block of code that executes in the case of the condition being false must return
— this is the true beauty of the guard statement.
You may hear programmers talking about the “happy path” through a function; this is the path you’d expect to happen most of the time. Any other path followed would be due to an error, or another reason why the function should return earlier than expected.
Guard statements ensure the happy path remains on the left hand side of the code; this is usually regarded as a good thing as it makes code more readable and understandable.
Also, because the guard statement must return in the false case, the Swift compiler knows that if the condition was true, anything checked in the guard statement’s condition must be true for the remainder of the function. This means the compiler
can make certain optimizations. You don’t need to understand how these optimizations work, or even what they are, since Swift is designed to be user- friendly and fast.