Using Optional value
We have seen in the previous articles how to declare variables and constants of type Optional<Wrapped>. We see that the value this optional is something like Optional(value), not the value itself.
For example:
var score: Int?
score = 20
print(score)
// Prints: Optional(20)
In the above code, the value of score is Optional(20), not 20. So, if you try to add this value to another Int, you will get an error. Or, even if you try to add an integer literal value, there will be an error.
For example:
var totalScore = 0
// Type of totalScore is Int - not Int?
// Since we assigned a literal integer, Swift does Type Inference and comes up with Int
totalScore += score
// Error - Int and Optional<Int> cannot be added together
score = score + 80
// Also gives an error - adding an Optional<Int> and integer literal (Int)
In both the cases above, the problem is that we are trying to add two different types. We can add two integers (Int type). But we cannot add one Int and one Optional<Int>. We cannot add even variables of type Optional<Int>.
var score2: Int?
score2 = 80
score = score + score2
// Error
In the above code, both score and score2 are of the same type - Int?. Even though these are of the same type, they cannot be added. This is because there is a global function in Swift that supports the + operator between two Int values:
public func +(lhs: Int, rhs: Int) -> Int
This operator function for + takes two Int values and returns an Int. No such global function exists for taking two Int? values. Just as a side note, many such predefined global operator functions exist for Float, Double, Int16, Int32, and so on.
Unwrapping
So, how do we get the Int value out of an Int? variable. This is done by using operator ! (exclamation point). This is called unwrapping the optional (using the ! is forced unwrapping of the optional). With !, you unwrap the optional to get the value inside. If the type is String?, unwrapping the variable or constant will give you the String value and so on.
var score: Int?
score = 20
print(score!)
// Prints: 20, not Optional(20)
When you print score!, the value 20 will be printed instead of Optional(20). The value is no longer Optional, but it is an Int.
Once you unwrap, you can use the + operator (and other available operators like -, *, /, etc.) between two variables of Int type.
score = score! + 80
// No error. Two Int values can now be added.
print(score)
// Prints: Optional(100)
print(score!)
// Prints: 100
In the first line above, first score! unwraps and gives an Int value 20, which can then be added to 80 another Int literal. This produces no error.
However, score itself remains a variable of type Int?. By using the ! operator, we unwrapped and got the value inside - type has not been changed. That’s why when you print score, it will still print Optional(100). If you want to print the unwrapped value, you need to print score!.
If the variable is Int (not Optional Int), then you don’t need to unwrap it.
var totalScore = 0
// Through Type Inference, type of totalScore is Int, not Int?
// This is same as:
// var totalScore: Int = 0
totalScore = totalScore + score!
print(totalScore)
// Prints: 100 - totalScore is Int, not an Optional Int
In the above code totalScore is of type Int. It is not an optional. Meaning, it must be initialized before it is used and it cannot hold a nil value (a no-value state). Since it is not optional, it doesn’t need to be unwrapped. When you are adding score to it, score needs to be unwrapped by adding !, because score is an optional.
When you print totalScore, there is need for !, because it is not an optional and doesn’t need to be wrapped. In fact, if you use totalScore!, there will be an error saying you cannot forcibly unwrap a non-optional.
Problems with forced unwrapping
You should use forced unwrapping of an optional only when you are sure that non-nil value exists inside.
var score: Int?
var totalScore = 0
totalScore += score!
// Crash: nil is not an Int
As in the above code, let’s say, score is declared as an Optional Int. That means, score will have a value of nil. Then you declared another variable called totalScore and assigned it a proper Int value. Here the type of totalScore by Type Inference is Int, not an Optional Int.
In the addition line above, you are unwrapping score by using ! and getting the Int value. Then you are adding this to another Int variable. This operation is perfectly legal. However, the problem here is that when you unwrap score, Swift didn’t find Int, but a nil because no Int value had been assigned. And that will result in a crash.
That means, you should only use forced unwrapping only when you are sure that the variable you are unwrapping has a non-nil value inside. In this case, may be don’t have a value for the score or the name or the id or whatever the variable you are using at the time of initialization. And you expect to get that before you unwrapped it. And in that case it is ok to use it.
Generally speaking, though, you want to limit the use of forced unwrapping (using !) as much as possible (as mentioned above, only in the surest cases). There are safer ways to unwrap an optional which we will discuss in the following articles.
Adding Optional Ints
If for some reason, you want to add two optional Ints (i.e. a situation where the standard function doesn’t exist), you can write one yourselves.
public func+(lhs: Int?, rhs: Int?) {
return lhs! + rhs!
}
var score1: Int? = 20
var score2: Int? = 30
print(score1+score2)
// Prints 50
Here, the + operator function is overloaded to take two Int?, instead of the built-in function that takes two Int values. Obviously, this is shown as way to write operator functions. But it suffers from forced unwrapping problems (lhs and rhs are forcibly unwrapped - and if those parameters come with nil value, this will crash. This just moves the ! from outside into a global function. The problems won’t disappear.
You want to use ! carefully.