Swift's guard keyword

Swift2Guard Statement

Swift2 Problem Overview


Swift 2 introduced the guard keyword, which could be used to ensure that various data is configured ready to go. An example I saw on this website demonstrates an submitTapped function:

func submitTapped() {
    guard username.text.characters.count > 0 else {
        return
    }

    print("All good")
}

I am wondering if using guard is any different than doing it the old fashioned way, using an if condition. Does it give benefits, which you could not get by using a simple check?

Swift2 Solutions


Solution 1 - Swift2

Reading this article I noticed great benefits using Guard

Here you can compare the use of guard with an example:

This is the part without guard:

func fooBinding(x: Int?) {
    if let x = x where x > 0 {
        // Do stuff with x
        x.description
    }
    
    // Value requirements not met, do something
}
  1. Here you’re putting your desired code within all the conditions

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.

But now we can use guard and we can see that is possible to resolve some issues:

func fooGuard(x: Int?) {
    guard let x = x where x > 0 else {
        // Value requirements not met, do something
        return
    }
    
    // Do stuff with x
    x.description
}

> 1. 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‘s else statement is run, which breaks out of the function. > 2. 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, the fooGuard(_:) function. > 3. You are checking for bad cases early, making your function more readable and easier to maintain

This same pattern holds true for non-optional values as well:

func fooNonOptionalGood(x: Int) {
    guard x > 0 else {
        // Value requirements not met, do something
        return
    }
    
    // Do stuff with x
}
 
func fooNonOptionalBad(x: Int) {
    if x <= 0 {
        // Value requirements not met, do something
        return
    }
    
    // Do stuff with x
}

If you still have any questions you can read the entire article: Swift guard statement.

Wrapping Up

And finally, reading and testing I found that if you use guard to unwrap any optionals,

> those unwrapped values stay around for you to use in the rest of your > code block

.

guard let unwrappedName = userName else {
	return
}

print("Your username is \(unwrappedName)")

Here the unwrapped value would be available only inside the if block

if let unwrappedName = userName {
	print("Your username is \(unwrappedName)")
} else {
	return
}

// this won't work – unwrappedName doesn't exist here!
print("Your username is \(unwrappedName)")

Solution 2 - Swift2

Unlike if, guard creates the variable that can be accessed from outside its block. It is useful to unwrap a lot of Optionals.

Solution 3 - Swift2

There are really two big benefits to guard. One is avoiding the pyramid of doom, as others have mentioned – lots of annoying if let statements nested inside each other moving further and further to the right.

The other benefit is often the logic you want to implement is more "if not let” than "if let { } else".

Here’s an example: suppose you want to implement accumulate – a cross between map and reduce where it gives you back an array of running reduces. Here it is with guard:

extension Sliceable where SubSlice.Generator.Element == Generator.Element {

    func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {
        // if there are no elements, I just want to bail out and
        // return an empty array
        guard var running = self.first else { return [] }

        // running will now be an unwrapped non-optional
        var result = [running]

        // dropFirst is safe because the collection
        // must have at least one element at this point
        for x in dropFirst(self) {
            running = combine(running, x)
            result.append(running)
        }
        return result
    }

}


let a = [1,2,3].accumulate(+)  // [1,3,6]
let b = [Int]().accumulate(+)  // []

How would you write it without guard, but still using first that returns an optional? Something like this:

extension Sliceable where SubSlice.Generator.Element == Generator.Element {
    
    func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {
        
        if var running = self.first  {
            var result = [running]

            for x in dropFirst(self) {
                running = combine(running, x)
                result.append(running)
            }
            return result
        }
        else {
            return []
        }
    }
    
}

The extra nesting is annoying, but also, it’s not as logical to have the if and the else so far apart. It’s much more readable to have the early exit for the empty case, and then continue with the rest of the function as if that wasn’t a possibility.

Solution 4 - Swift2

When a condition is met using guard it exposes variables declared within the guard block to the rest of the code-block, bringing them into its scope. Which, as previously stated, will certainly come in handy with nested if let statements.

Note that guard requires a return or a throw in its else statement.

Parsing JSON with Guard

Below is an example of how one might parse a JSON object using guard rather than if-let. This is an excerpt from a blog entry that includes a playground file which you can find here:

How to use Guard in Swift 2 to parse JSON

func parseJSONWithGuard(data : [String : AnyObject]) throws -> Developer {
    
    guard let firstname = data["First"] as? String  else {
        return Developer() // we could return a nil Developer()
    }
    
    guard let lastname = data["Last"] as? String else {
        throw ParseError.BadName // or we could throw a custom exception and handle the error
    }

    guard let website = data["WebSite"] as? String else {
        throw ParseError.BadName
    }

    guard let iosDev = data["iosDeveloper"] as? Bool else {
        throw ParseError.BadName
    }



    return Developer(first: firstname, last: lastname, site: website, ios: iosDev)

}

download playground: guard playground

More info:

Here's an excerpt from the The Swift Programming Language Guide:

> 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 > that that guard statement appears in. It can do this with a control > transfer statement such as return, break, or continue, or it can call > a function or method that doesn’t return, such as fatalError().

Solution 5 - Swift2

One benefit is elimination a lot of nested if let statements. See the WWDC "What's New in Swift" video around 15:30, the section titled "Pyramid of Doom".

Solution 6 - Swift2

When to use guards

If you’ve got a view controller with a few UITextField elements or some other type of user input, you’ll immediately notice that you must unwrap the textField.text optional to get to the text inside (if any!). isEmpty won’t do you any good here, without any input the text field will simply return nil.

So you have a few of these which you unwrap and eventually pass to a function that posts them to a server endpoint. We don’t want the server code to have to deal with nil values or mistakenly send invalid values to the server so we’ll unwrap those input values with guard first.

func submit() {
    guard let name = nameField.text else {
        show("No name to submit")
        return
    }

    guard let address = addressField.text else {
        show("No address to submit")
        return
    }

    guard let phone = phoneField.text else {
        show("No phone to submit")
        return
    }

    sendToServer(name, address: address, phone: phone)
}

func sendToServer(name: String, address: String, phone: String) {
  ...
}

You’ll notice that our server communication function takes non-optional String values as parameters, hence the guard unwrapping beforehand. The unwrapping is a little unintuitive because we’re used to unwrapping with if let which unwraps values for use inside a block. Here the guard statement has an associated block but it’s actually an else block - i.e. the thing you do if the unwrapping fails - the values are unwrapped straight into the same context as the statement itself.

// separation of concerns

Without guard
Without using guard, we’d end up with a big pile of code that resembles a pyramid of doom. This doesn’t scale well for adding new fields to our form or make for very readable code. Indentation can be difficult to follow, particularly with so many else statements at each fork.

func nonguardSubmit() {
    if let name = nameField.text {
        if let address = addressField.text {
            if let phone = phoneField.text {
                sendToServer(name, address: address, phone: phone)
            } else {
                show("no phone to submit")
            }
        } else {
            show("no address to submit")
        }
    } else {
        show("no name to submit")
    }
}

Yes, we could even combine all these if let statements into a single statement separated with commas but we would loose the ability to figure out which statement failed and present a message to the user.

https://thatthinginswift.com/guard-statement-swift/

Solution 7 - Swift2

With using guard our intension is clear. we do not want to execute rest of the code if that particular condition is not satisfied. here we are able to extending chain too, please have a look at below code:

guard let value1 = number1, let value2 = number2 else { return }
 // do stuff here

Solution 8 - Swift2

Guard statement going to do . it is couple of different

  1. it is allow me to reduce nested if statement
  2. it is increase my scope which my variable accessible

if Statement

func doTatal(num1 : Int?, num2: Int?) {
  // nested if statement
    if let fistNum = num1 where num1 > 0 {
        if let lastNum = num2 where num2 < 50 {
            
          let total = fistNum + lastNum
        }
    }
 // don't allow me to access out of the scope 
 //total = fistNum + lastNum 
}

Guard statement

func doTatal(num1 : Int?, num2: Int?) {
   //reduce  nested if statement and check positive way not negative way 
    guard let fistNum = num1 where num1 > 0 else{
      return
    }
    guard  let lastNum = num2 where num2 < 50 else {
     return
    }
    // increase my scope which my variable accessible
    let total = fistNum + lastNum
    
}

Solution 9 - Swift2

> From Apple documentation:

Guard Statement

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

Synatx:

guard condition else {
    statements
}

Advantage:

1. By using guard statement we can get rid of deeply nested conditionals whose sole purpose is validating a set of requirements.

2. It was designed specifically for exiting a method or function early.

if you use if let below is the code how it looks.

  let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        
        if error == nil {
            if let  statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 {
                if let data = data {
                    
                    //Process Data Here.
                    print("Data: \(data)")
                    
                } else {
                    print("No data was returned by the request!")
                }
            } else {
                print("Your request returned a status code other than 2XX!")
            }
        } else {
            print("Error Info: \(error.debugDescription)")
        }
    }
    task.resume()

Using guard you can transfer control out of a scope if one or more conditions aren't met.

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
            
            /* GUARD: was there an error? */
            guard (error == nil) else {
                print("There was an error with your request: \(error)")
                return
            }
            
            /* GUARD: Did we get a successful 2XX response? */
            guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 else {
                print("Your request returned a status code other than 2XX!")
                return
            }
            
            /* GUARD: was there any data returned? */
            guard let data = data else {
                print("No data was returned by the request!")
                return
            }
            
            //Process Data Here.
            print("Data: \(data)")
}
task.resume()

Reference:

*1. Swift 2: Exit Early With guard 2. Udacity

  1. Guard Statement*

Solution 10 - Swift2

Like an if statement, guard executes statements based on a Boolean value of an expression. Unlike an if statement, guard statements only run if the conditions are not met. You can think of guard more like an Assert, but rather than crashing, you can gracefully exit.

refer to: http://ericcerney.com/swift-guard-statement/

Solution 11 - Swift2

It really really does make the flow of a sequence with several lookups and optionals much more concise and clear and reduces lots of if nesting. See Erica Sadun post on replacing Ifs. .... Could get carried away, an example below:

    let filteredLinks = locationsLinkedToList.filter({$0.actionVerb == movementCommand})
    guard let foundLink = filteredLinks.first else {return ("<Person> cannot go in that direction.", nil, nil)}
    guard filteredLinks.count == 1 else {return ("<Person> cannot decide which route to take.", nil, nil)}
    guard let nextLocation = foundLink.toLocation else {return ("<Person> cannot go in that direction.", nil, nil)}

See if that sticks.

Solution 12 - Swift2

Simply put, it provides a way to validate fields prior to execution. This is a good programming style as it enhances readability. In other languages, it may look like this:

func doSomething() {
    if something == nil {
        // return, break, throw error, etc.
    }
    ...
}

But because Swift provides you with optionals, we can't check if it's nil and assign its value to a variable. In contrast, if let checks that it's not nil and assigns a variable to hold the actual value. This is where guard comes into play. It gives you a more concise way of exiting early using optionals.

Solution 13 - Swift2

Source: Guard in Swift

Let's see the example to understand it clearly

Example 1:

func validate() {         
    guard 3>2 else {             
    print ("False")             
    return         
    }         
    print ("True") //True     
} 
validate()

In the above example we see that 3 is greater than 2 and the statement inside the guard else clause are skipped and True is printed.

Example 2:

func validate() {         
    guard 1>2 else {             
    print ("False")            //False 
    return         
    }         
    print ("True")      
} 
validate()

In the above example we see that 1 is smaller than 2 and the statement inside the guard else clause are executed and False is printed followed by return.

Example 3: gaurd let, unwrapping optionals through guard let

func getName(args myName: String?) {
     guard let name = myName, !name.isEmpty else {
     print ("Condition is false")          // Condition is false            return         
     }         
     print("Condition is met\(name)")     
} 
getName(args: "")

In the above example we are using guard let to unwrap the optionals. In the function getName we’ve defined a variable of type string myName which is optional. We then use guard let to check whether the variable myName is nil or not, if not assign to name and check again, name is not empty. If both the conditions qualified i.e. true the else block will be skipped and print “Conditions is met with name”.

Basically we are checking two things here separated by comma, first unwrapping and optional and checking whether that satisfies condition or not.

Here we are passing nothing to the function i.e. empty string and hence Condition is false is print.

func getName(args myName: String?) {
     guard let name = myName, !name.isEmpty else {
     print ("Condition is false")          
     return         
     }        
     print("Condition is met \(name)") // Condition is met Hello    
} getName(args: "Hello")

Here we are passing “Hello” to the function and you can see the output is printed “Condition is met Hello”.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid SnabelView Question on Stackoverflow
Solution 1 - Swift2Jorge CasariegoView Answer on Stackoverflow
Solution 2 - Swift2takebayashiView Answer on Stackoverflow
Solution 3 - Swift2Airspeed VelocityView Answer on Stackoverflow
Solution 4 - Swift2Dan BeaulieuView Answer on Stackoverflow
Solution 5 - Swift2zaphView Answer on Stackoverflow
Solution 6 - Swift2mfaaniView Answer on Stackoverflow
Solution 7 - Swift2Narendra GView Answer on Stackoverflow
Solution 8 - Swift2Nazmul HasanView Answer on Stackoverflow
Solution 9 - Swift2Ashok RView Answer on Stackoverflow
Solution 10 - Swift2ZgpeaceView Answer on Stackoverflow
Solution 11 - Swift2DavidSView Answer on Stackoverflow
Solution 12 - Swift2gunbyView Answer on Stackoverflow
Solution 13 - Swift2AdityaView Answer on Stackoverflow