Swift: Use Cases For Guard
The keyword guard has been introduced in Swift 2. It was a little bit inconspicuous at the first sight, but it has a lot of power. In this article we will take a look at three uses cases for guard.
Hint: This post has been updated to Swift 3 and Xcode 8
Avoiding The Pyramid Of Doom
Using guard is very good way to avoid the pyramid of doom. Let’s take a look at an example from a previous post. We are creating a function that calculates the area of a circle:
import Foundation enum CircleAreaCalculationError: Error { case RadiusNotSpecified case RadiusUnvalid } func calculateCirlceArea(radius:Double?) throws -> Double { if let radius = radius { if radius > 0 { return radius*radius*M_PI } else { throw CircleAreaCalculationError.RadiusUnvalid } } else { throw CircleAreaCalculationError.RadiusNotSpecified } }
It works, but you can see that there are a lot of if and else keywords. And that’s not very good to read. If you have a lot of nested indentations, you are speaking of “the pyramid of doom”. Our example is not very extreme, but there are a lot of real world examples where you have a lot of nested indentations.
By using guard you can make the code much more readable:
import Foundation enum CircleAreaCalculationError: Error { case RadiusNotSpecified case RadiusUnvalid } func calculateCirleArea(radius:Double?) throws -> Double { guard let radius = radius else { throw CircleAreaCalculationError.RadiusNotSpecified } guard radius > 0 else { throw CircleAreaCalculationError.RadiusUnvalid } return radius*radius*M_PI }
There’s also see another great benefit in this example: If you are using guard for unwrapping an optional, the variable becomes available as a non-optional after the guard block. By using optional chaining you can only use it within the if block.
Throwing Errors
Since Swift 2 there’s been a complete new error handling model. It uses a do-try-catch syntax. As you can see in the previous example, guard is a very good place to throws errors:
guard radius > 0 else { throw CircleAreaCalculationError.RadiusUnvalid }
In my opinion that is an excellent use case for guard.
API Availability Checking
Every year Apple releases a new major iOS update, and with each update there are new features and APIs. But since it is not unusual for an App to support at least the previous iOS version, you have to be careful in using these new APIs. The API availability checking feature is very handy in these situations.
Without using guard, you can do this for example like this:
func configureForceTouch() { if #available(iOS 9.0, *) { if (traitCollection.forceTouchCapability == UIForceTouchCapability.available) { //configure force touch } } }
By using guard, your code becomes much more readable:
func configureForceTouch() { guard #available(iOS 9.0, *) else { return } if (traitCollection.forceTouchCapability == UIForceTouchCapability.available) { //configure force touch } }
This is also a special case of avoiding the pyramid of doom.
Video
References
Optionals In Swift
Swift 2: guard
Swift 2.0: API Availability Checking
Image: @ David Pereiras / shutterstock.com