Ways to Unwrap Optionals in Swift

In this post I will explain all the possible ways to unwrap an optional in Swift.

Lets look at them one by one with their uses and consequences of using them

Force Unwrapping

This is the easiest way to unwrap an optional and that’s why tempting. You need to just put exclamation mark (!) after the optional value and you get the unwrapped value

var a : Int? = 5
print(a!)
var b = a!

So in the above piece of code we have declared an optional Int a, unwrapping its value using force unwrapping and assigning it to b. The type of b would be Int and not optional Int, meaning that b can not be assigned nil. You can try that.

var a : Int? = 5
print(a!)
var b = a!
b = nil // Error 

So this is the simplest way to unwrap optional. Why should we have other ways?
Consider following

var a : Int? 
var b = a! // fatal error: unexpectedly found nil while unwrapping an Optional value

Here a is declared optional Int but not assigned any value, so it holds nil. When we try to force unwrap it with !, it results in runtime exception saying “fatal error: unexpectedly found nil while unwrapping an Optional value”.
So if you use force unwrapping you should be sure that the optional actually contains some value, its better to avoid force unwrapping and letting your program to probably fall into runtime exceptions.
Lets see how can we avoid that.

Safely Unwrapping by Checking for nil

To avoid runtime exceptions you can first make sure that the value you are trying to unwrap is not nil using if block. You can do this like

var a : Int?
var b = 0
// safety check
if a != nil {
    b = a!
}

In the above case a would be first checked to be not nil and then only b would be assigned the unwrapped value of a. So there would be not be any chance for b to have nil value and cause runtime exception.

Unwrapping with if let binding

Unwrapping optionals using if is also called as optional binding.
In this method we use if to assign the optional to a variable or constant, which is available in the scope of if block. It takes the following form

if let variable1 = optional1 {
    //use variable1 here
} else {
   // optional1 was holding nil thats why else block is executing 
}

You can unwrap multiple optionals in single statement as follows

if let variable1 = optional1, let variable2 = optional2 {
   // use variable1 and variable2 here, which are guaranteed to be not nil
} else {
   // either optional1 was nil or optional2 was nil or both were nil 
}

You can even combine other conditions with optional binding if statement like following

if let variable1 = optional1, variable1 < 500 {
    // variable1 is not nil and less than 500
} else {
   // either variable1 is nil or it is not less than 500
}

It is to be noted that the else block is optional here(Which is not the case guard let statement). Also the entities declared in if statement are available only in if block.

Lets take an example to understand optional binding with if statement in Swift.
Apple has provided excellent example for this one in there documents. We will try to understand with similar example.

You can initialise Int with String. But the string must be convertible to Int. Int has an initialiser which takes a String as argument and returns Int value if the passed String is successfully converted to Int otherwise it returns nil. So

var number = Int("10")

would assign Int 10 to number.
But

var number = Int("abc")

would assign nil to number.

Now lets assume that you get some numberString1 and numberString2 from either server or user input filed. User is free to enter characters other than numbers. You would like make sure that you can get the number out of these Strings. ( You can handle the conditions where the Strings cannot be converted to numbers)
You can easily do it using optional binding with if statement as following

if let number1 = Int(numberString1) {
   print("\(numberString1) is an Int")
} else {
  print("\(numberString1) is an not an Int")
}

As I mentioned earlier you can combine unwrapping of multiple optionals in single if like

if let number1 = Int(numberString1), let number2 = Int(numberString2) {
    print("\(NumberString1) and \(numberString2) are Integers")
} else {
    print("Printing this because either \(numberString1) or \(numberString2) or both are not Integers.")
}

You can also combine other conditions with optional binding if conditions in Swift like

if let number1 = Int(numberString1), let number2 = Int(numberString2), number1 < 50 {
    print("\(numberString1) and \(number2) are Integers and \(numberString1) is less than 50")
} else {
    print("Printing this because either \(numberString1) or \(numberString2) or both are not Integers. Or \(numberString1) is greater than 50")
}

Entities declare in if let statement are only available in if block. If you try to access it anywhere else you will get compile time error. For example

if let number1 = Int(numberString1) {
   print("\(numberString1) is an Int")
} else {
  print("Trying to access \(number1)") // error: use of unresolved identifier 'number1'
}
print("Let me try to access \(number1) here") // error: use of unresolved identifier 'number1'

So this was how you can use optional binding using if in Swift.
Now lets move onto our next unwrapping method

Unwrapping with guard

guard is mainly used to check conditionswhich must be satisfied for the rest of the code after guard to do any useful thing. Either the conditions in guard statement are met or the execution must be taken out from the scope in which guard statement is defined. For detailed information about guard and its difference with if you can read this.
We will concentrate on unwrapping optionals using guard here. Unwrapping optionals with guard is very simple Swift. You can do this as following

 
guard let aValue = SomeOptional  else {
   // take control out of the block in which guard is defined. 
}

We can extend our previous example. Lets say we are getting numberString1 and numberString2, we want to convert these to Int and return the greater of the two via a function. We can make use of guard in this case like this

 
func findGreateer(numberString1 : String , numberString2 : String) -> Int? {
    guard let number1 = Int(numberString1) , let number2 = Int(numberString2) else {
        print("Atleast one of \(numberString1) or \(numberString1) is not an integer")
        return nil
    }
    
    return number1 > number2 ? number1 : number2
}

One of the main thing here is the number1 and number2 are available here for use after guard statement.

Now lets see the next way to unwrap an optional value in Swift

Unwrapping with Nil-Coalescing Operator

Let there be some optional value optional1. You want to make sure that a variable a is assigned the value of optional1 only if optional1 is not nil. Otherwise you want to assign a some default value. You can achieve this using ternary conditional operator like this

 
let a = optional1 != nil ? optional1 ? defaultValue

There is an easier and cleaner operator provided by Swift to achieve the above represent by ?? and called Nil-Coalescing Operator. To achieve the above using Nil-Coalescing Operator you can do the following

let a = optional1 ?? defaultValue

The above code will assign optional1 value to a only if optional1 is not nil. Otherwise it will assign defaultValue to a.

Lets take another example to understand this. Lets say there is a String numberString1. We would like to assign it number variable, if it is convertible to Int otherwise we will assign 0 to number. We can achieve this simply like this

let number = Int(numberString1) ?? 0

As simple as that.
So above are all the ways in which a value hold by an optional can be unwrapped and used.

Advertisements

One thought on “Ways to Unwrap Optionals in Swift

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s