Chapter 4. To Be or Not To Be – Optionals

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:

  • Defining an optional
  • Unwrapping an optional
  • Optional chaining
  • Implicitly unwrapped optionals
  • Debugging optionals
  • The underlying implementation

Defining an optional

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset