When the first saw the Swift guard
statement during Apple’s Platform State of the Union, I couldn’t quite understand why I would ever use it. So what is it?
Like an
if
statement,guard
executes statements based on a Boolean value of an expression. Unlike anif
statement,guard
statements only run if the conditions are not met. You can think ofguard
more like anAssert
, but rather than crashing, you can gracefully exit.
Even after seeing some examples, I only saw it as a confusing way to accomplish what we already could with Optional Binding or with if-else
statements alone.
Diving In
Let’s take a simple example comparing current techniques vs using the new guard
statement:
1 func fooManualCheck(x: Int?) { 2 if x == nil || x <= 0 { 3 // Value requirements not met, do something 4 return 5 } 6 7 // Do stuff with x 8 x!.description 9 }
This is the most basic Objective-C style way to make sure a value exists and that it meets a condition. Now this works fine, but has a couple flaws:
- You’re checking for a condition that you don’t want, rather than checking for the value you do want. Code becomes confusing when you have a bunch of checks like this. What you’re hoping for here is that your condition actually doesn’t pass.
- You also need to force unwrap the optional value after the condition fails.
Swift gave us a way to clean this up and fix some of these flaws through Optional Binding:
1 func fooBinding(x: Int?) { 2 if let x = x where x > 0 { 3 // Do stuff with x 4 x.description 5 } 6 7 // Value requirements not met, do something 8 }
This removes both of the flaws that the first function had, but adds a new one. Here you’re putting your desired code within all the conditions, rather than afterward. You might not immediately see a problem with this, but you could imagine how confusing it could become if it was nested with numerous conditions that all needed to be met before running your statements.
The way to clean this up is to do each of your checks first, and exit if any aren’t met. This allows easy understanding of what conditions will make this function exit.
I’ve heard this called the Bouncer Pattern, which makes a lot of sense. You want to get rid of the bad cases before they get in the door. It also allows you to think about one case at a time, rather than figuring out how all combinations need to work together.
Here enters the guard
statement:
1 func fooGuard(x: Int?) { 2 guard let x = x where x > 0 else { 3 // Value requirements not met, do something 4 return 5 } 6 7 // Do stuff with x 8 x.description 9 }
Using guard
solves all 3 of the issues mentioned above:
- Checking for the condition you do want, not the one you don’t. This again is similar to an
assert
. If the condition is not met,guard
‘selse
statement is run, which breaks out of the function. - If the condition passes, the optional variable here is automatically unwrapped for you within the scope that the
guard
statement was called – in this case, thefooGuard(_:)
function. This is an important, yet notably strange feature that really makes theguard
statement useful. - You are checking for bad cases early, making your function more readable and easier to maintain.
The cool thing is that this same pattern holds true for non-optional values as well:
1 func fooNonOptionalGood(x: Int) { 2 guard x > 0 else { 3 // Value requirements not met, do something 4 return 5 } 6 7 // Do stuff with x 8 } 9 10 func fooNonOptionalBad(x: Int) { 11 if x <= 0 { 12 // Value requirements not met, do something 13 return 14 } 15 16 // Do stuff with x 17 }
Wrapping Up
This simple example shows how you could start using guard
immediately in your Swift code to make your function/methods more clear. It’s easy for us to immediately judge the value of a new feature until you give it a chance and see what it can or can’t do for you.
Going from Objective-C to Swift is a huge change, not only to syntax, but how you have to look at architecting your code. You can only benefit from this awesome new language if you actively change your mindset while writing code by expanding your everyday patterns and style.
Reference:Swift Guard Statement
Reference:Swift的Guard语句