Swift Optionals

In the previous article, we learned about different data types available in Swift and also noticed variable or constant declared of those types contains a default value.

Example:

let someValue = Int()
print(someValue)

When you run the program, the output will be:

0

However there is another data type in Swift called Optional, whose default value is a null value (nil). You can use optional when you want a variable or constant contain no value in it. An optional type may contain a value or absent a value (a null value).

Non technically, you can think optional as a shoe box. The shoe box may or may not contain a shoe in it. So, you should know beforehand while accessing the shoe from the box.


How to declare an Optional?

You can simply represent a Data type as Optional by appending ! or ? to the Type. If an optional contains a value in it, it returns value as Optional<Value>, if not it returns nil.

Example 1: How to declare an optional in Swift?

var someValue:Int?
var someAnotherValue:Int!
print(someValue)
print(someAnotherValue)

When you run the program, the output will be:

nil
nil

In the above program, we have initialized a optional type using ? and !. Both ways are valid to create an optional but there is one major difference which we will explore below.

Declaring an optional Int means the variable will either have an integer value or no value. Since no value is assigned to the variable, you can see both print statement outputs nil on the screen.


Example 2: Assigning and accessing a value from an optional

let someValue:Int? = 5
print(someValue)
print(someValue!)

When you run the program, the output will be:

Optional(5)
5

In the above program, we have declared an optional of Int type and assigned value 5 in it.

As you can see, printing the optional as print(someValue) doesn't give you 5 but Optional(5). It is of the form as described above: Optional<Value>. In order to access the <Value> from it, we need a mechanism called unwrapping.

You can unwrap an optional by appending ! character at the end of the variable/constant as in the next line print(someValue!). print(someValue!) unwraps the optional and outputs 5 on the screen.

However, remember, this kind of unwrapping mechanism should only be used when you are certain that the optional will sure have a value when you access it.


Example 3: Explicitly declaring an unwrapped optional

You can also create an unwrapped optional as:

let someValue:Int! = 5
print(someValue)

When you run the program, the output will be:

5

In the above program, Int! creates a unwrapped optional, which automatically unwraps the value while you access it so that you don't need to everytime append the ! character.

Be certain while you use these kinds of optionals, the variable will always need to have a value when you access it. If you don't, you will get a fatal error crash.


Example 4: Fatal error when accessing a null unwrapped optional

var someValue:Int!
var unwrappedValue:Int = someValue //crashes due to this line

When you run the program, you will get a crash as fatal error: unexpectedly found nil while unwrapping an Optional value because the code unwrappedValue:Int = someValue tries to assign value from Optional someValue to variable unwrappedValue.

However, somevalue is an Optional type that contains nil value. Trying to assign nil value to variable unwrappedValue which is not an optional will lead to crash.

There are different techniques to handle this case which are explained below.


Optional Handling

In order to use value of an optional, it needs to be unwrapped. Better way to use optional value is by conditional unwrapping rather than force unwrapping using ! operator.

This is because conditionally unwrapping asks Check if this variable has a value? . If yes, give the value, otherwise it will handle the nil case.

On the contrary, force unwrapping says This variable does have a value while you use it. Therefore, when you force unwrap a variable that is nil, your program will throw an unexpectedly found nil while unwrapping an optional exception and crash. Some of the techniques for conditional unwrapping are explained below:

1. If-statement

You can use if statement and compare optional with nil to find out whether a optional contains a value or not. You can use the comparison operator "equal to" operator (==) or the "not equal to" operator (!=) in the if statement.

Example 5: Optional handling with if else statement

var someValue:Int?
var someAnotherValue:Int! = 0
        
if someValue != nil {
	print("It has some value \(someValue!)")
} else {
	print("doesn't contain value")
}
        
if someAnotherValue != nil {
	print("It has some value \(someAnotherValue!)")
} else {
	print("doesn't contain value")
}

When you run the program, the output will be:

doesn't contain value
It has some value 0

In the above program, the code inside if statement executes if an optional contain a value, otherwise the statement inside the else block executes. The major drawback of optional handling using this technique is, you still need to unwrap the value from optional using ! operator.


2. Optional Binding (if-let)

Optional binding helps you to find out whether an optional contains a value or not. If an optional contains a value, that value is available as a temporary constant or variable. Therefore, optional binding can be used with if statement to check for a value inside an optional, and to extract that value into a constant or variable in a single action.

Example 5: Optional handling using if let statement

var someValue:Int?
var someAnotherValue:Int! = 0
       
if let temp = someValue {
	print("It has some value \(temp)") 
} else {
	print("doesn't contain value")
}
        
if let temp = someAnotherValue {
	print("It has some value \(temp)")
} else {
	print("doesn't contain value")      
}

When you run the program, the output will be:

doesn't contain value
It has some value 0

In the above program, the code inside if statement executes if the optional contains a value. Otherwise the else block gets executed. The if-let statement also automatically unwraps the value and places the unwrapped value in temp constant. This technique has major advantage because you don't need to forcely unwrap the value although being certain an optional contains a value.


3. Guard statement

You can use guard to handle optionals in Swift. Don't worry if you don't know what guard is. For now, just think of guard as an if-else condition with no if block. If the condition fails, else statement is executed. If not, next statement is executed. See Swift guard for more details.

Example 6: Optional handling using guard-let

func testFunction() {
	let someValue:Int? = 5
	guard let temp = someValue else {
		return
	}
	print("It has some value \(temp)")
}

testFunction()

When you run the program, the output will be:

It has some value 5

In the above program, the guard contains a condition whether an optional someValue contains a value or not. If it contains a value then guard-let statement automatically unwraps the value and places the unwrapped value in temp constant. Otherwise, else block gets executed and and it would return to the calling function. Since, the optional contains a value, print function is called.


4. Nil-coalescing operator

In Swift, you can also use nil-coalescing operator to check whether a optional contains a value or not. It is defined as (a ?? b). It unwraps an optional a and returns it if it contains a value, or returns a default value b if a is nil.

Example 7: Optional handling using nil-coalescing operator

var someValue:Int!
let defaultValue = 5
let unwrappedValue:Int = someValue ?? defaultValue
print(unwrappedValue)

When you run the program, the output will be:

5

In the above program, variable someValue is defined optional and contains nil value. The nil coalescing operator fails to unwrap the optional therefore returns defaultValue. Therefore the statement print(unwrappedValue) outputs 5 in the console.

var someValue:Int? = 10
let defaultValue = 5
let unwrappedValue:Int = someValue ?? defaultValue
print(unwrappedValue)

When you run the program, the output will be:

10

However, in the above program, optional variable someValue is initialized with value 10. So, the nil coalescing operator successfully unwraps the value from someValue. Therefore, the statement someValue ?? defaultValue returns 10 and the statement print(unwrappedValue) outputs 10 in the console.