In my previous article about swift optionals, I mentioned about optional binding.
? Optional Binding (if -let statements) :
Use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable.
An optional binding for the if statement is as follows ?
if let constantName = someOptional { //statements using ‘constantName’ } else { // the value of someOptional is not set (or nil).}
Optional binding is the recommended way of unwrapping optionals.This method is safer than force unwrapping and implicit unwrapping. Refer this article for more info on this concept.
? if -var statements :
If you use the let then you will not be able to change myValue.
if let myValue = myObject.value as NSString? { myValue = “Something else” // <– Compiler error}
On the other hand with var you can.
let someOptionalString:String?someOptionalString = “abcd”if var varString = someOptionalString {print(varString) //prints abcdvarString = “efgh”print(varString) //prints efgh} else {// the value of someOptionalString is not set (or nil).}
Please note that myValue does exists only within the scope of the if and changing its value does not produce effect outside of its scope. So, in most cases the if- var statement will be useless.
The drawback of if let and if var statements are that any variables or constants that were assigned values using an optional binding are availabe only within the scope of the if statement brackets.
? Guard Statement :
Guard statement is simple and powerful. It checks for some condition and if it evaluates to be false, then the else statement executes which normally will exit a method .
A guard let statement is another way of writing an if let statement written in a different way. 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.”
Unlike if let statements, 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.
A guard block only runs if the condition is false, and it will exit out of the code block through a control transfer statement like return, break, continue, or thrown. It provides an early exit and fewer brackets. Early exit means faster execution.
If the condition is true, Swift ignores the guard block.
Other than optional binding, guard statements can be used for normal validation checks as well.
func submitForms(result:Bool) {guard result == true else {print(?result is false?)return}}
These are like simple optional binding and condition checks. But guard statements will come extremely handy for multi level condition checks like password validation and related stuffs.
func validatePassword(password:String) ->Bool{guard password.characters.count > 3 else {print(?Password should contain atleast 3 characters?)return false}guard password.characters.count > 13 else {print(?Password should contain more than 13 characters?)return false}guard checkPasswordCharacterSet(password) else {print(?Password should contain one capital letter , one small letter, one special character?)return false}return true}
If we had to use if-let statements, we would have written a pyramid of doom of code. Also, guard statements are easy to understand.
? guard – var
If var binding is some what useless as the scope of the optional unwrapped by optional binding is within the scope of if statement. But guard-var might be useful. Check the following code.
let a: Int? = 40func doSomething(passedA:Int?) {guard var b = passedA else {return}print (b) // prints 40b = 100print (b) // prints 100}doSomething(passedA: a)
Special case with guard statement: Optional Bool
I came across this scenario once and was confused at this point. I am adding it here just to avoid this confusion . Not a big deal ?. Let us check the following code.
Here the guard let statement check if the optionalBool variable is nil or not.
guard let is doing optional binding and it will only check for nil value and execute the guard block if the condition is false. ie; optionalBool is nil.
The second guard statement checks if the boolValue is true or false.
? Defer statement :
Source: Apple docs
You use a defer statement to execute a set of statements just before code execution leaves the current block of code. This statement lets you do any necessary cleanup that should be performed regardless of how execution leaves the current block of code?whether it leaves because an error was thrown or because of a statement such as return or break. For example, you can use a defer statement to ensure that file descriptors are closed and manually allocated memory is freed.
A defer statement defers execution until the current scope is exited. This statement consists of the deferkeyword and the statements to be executed later. The deferred statements may not contain any code that would transfer control out of the statements, such as a break or a return statement, or by throwing an error. Deferred actions are executed in reverse order of how they are specified?that is, the code in the first deferstatement executes after code in the second, and so on.
func doSomething() {defer { print(?1?)}defer { print(?2?)}defer { print(?3?)}if 1<2 {defer { print(“1<2”)}}defer { print(?4?)}defer { print(?5?)}defer { print(?6?)}}
Can you guess the order of execution?
The defer statement inside the if code block will be executed first. Then it follows a LIFO pattern to execute the rest of the defer statements.
It will print :
1<2654321
Enjoy!!