As we discussed in Chapter 2, Building Blocks – Variables, Collections, and Flow Control, all variables and constants must always have a value before they are used. This is a great safety feature because it prevents you from creating a scenario where you forget to give a variable an initial value. It may make sense for some number variables, such as the number of sandwiches ordered to start at zero, but it doesn't make sense for all variables. For example, the number of bowling pins standing should start at 10, not zero. In Swift, the compiler forces you to decide what the variable should start at, instead of providing a default value that could be incorrect.
However, there are other scenarios where you will have to represent the complete absence of a value. A great example is if you have a dictionary of word definitions and you try to lookup a word that isn't in the dictionary. Normally, this will return a String, so you could potentially return an empty String, but what if you also need to represent the idea that a word exists without a definition? Also, for another programmer who is using your dictionary, it will not be immediately obvious what will happen when they look up a word that doesn't exist. To satisfy this need to represent the absence of a value, Swift has a special type called an optional.
In this chapter, we will cover the following topics:
So we know that the purpose of optionals in Swift is to allow the representation of the absence of a value, but what does that look like and how does it work? An optional is a special type that can "wrap" any other type. This means that you can make an optional String
, optional Array
, and so on. You can do this by adding a question mark (?
) to the type name, as shown:
var possibleString: String? var possibleArray: [Int]?
Note that this code does not specify any initial values. This is because all optionals, by default, are set to no value at all. If we want to provide an initial value we can do so similar to any other variable:
var possibleInt: Int? = 10
Also, note that if we left out the type specification (: Int?
), possibleInt
would be inferred to be of type Int
instead of an optional Int
.
Now, it is pretty verbose to say that a variable lacks a value. Instead, if an optional lacks a variable, we say it is nil. So both possibleString
and possibleArray
are nil, while possibleInt
is 10
. However, possibleInt
is not truly 10
. It is still wrapped in an optional.
You can see all the forms a variable can take by putting the following code into a playground:
var actualInt = 10 var possibleInt: Int? = 10 var nilInt: Int? print(actualInt) // 10 print(possibleInt) // Optional(10) print(nilInt) // nil
As you can see, actualInt
prints out just as we expected, but possibleInt
prints out as an optional that contains the value 10
instead of just 10
. This is a very important distinction because an optional cannot be used as the value it is wrapping. nilInt
just reports that it is nil. At any point, you can update the value within an optional; this includes assigning it a value for the first time, using the assignment operator (=
):
nilInt = 2 print(nilInt) // Optional(2)
You can even remove the value within an optional by assigning it to nil
:
nilInt = nil print(nilInt) // nil
So we have this wrapped form of a variable that may or may not contain a value. What do we do if we need to access the value within an optional? The answer is that we must unwrap it.