Optional variables
All of the variables that we have looked at so far are considered to be nonoptional variables. This means that the variables are required to have a non-nil value; however, there are times when we want or need our variables to contain nil values. This can occur if we return a nil from a function whose operation failed or if a value is not found.
In Swift, an optional variable is a variable that we are able to assign nil (no value) to. Optional variables and constants are defined using ?
(question mark). Let's look at the following Playground; it shows us how to define Optional
and shows what happens if we assign a nil value to a Non-Optional
variable:
Notice the error we receive when we try to assign a nil value to the nonoptional variable. This error message tells us that the stringTwo
variable does not conform to the NilLiteralConvertible
protocol. What this tells us is that we are assigning a nil value to a variable or constant that is not defined as an optional type.
Optionals were added to the Swift language as a safety feature. Optionals provide a compile time check of our variables to verify that they contain a valid value. Unless our code specifically defines a variable as optional, we can assume that the variable contains a valid value and we do not have to check for nil values. Since we are able to define a variable prior to initiating it, this could give us a nil value in a nonoptional variable; however, the compiler checks for this as well. The following Playground shows the error that we receive if we attempt to use a nonoptional variable prior to initiating it:
To verify that an optional variable or constant contains a valid (non-nil) value, our first thought may be to use the !=
(not equals to) operator to verify that the variable is not equal to nil, but there are also other ways. These other ways are Optional Binding and Optional Chaining. Before we cover optional binding and optional chaining, let's see how to use the !=
(not equals to) operator and force unwrapping.
To use force unwrapping, we must first make sure that the optional has a non-nil value, and then we can use the explanation point to access that value. The following example shows how to do this:
var name: String? Name = "Jon" if name != nil { var newString = "Hello " + name! }
In this example, we create an optional variable named name
and we assign it a value of Jon
. We then use the !=
operator to verify that the optional is not equal to nil. If it is not equal to nil, we are then able to use the explanation point to access its value. While this is a perfectly viable option, it is recommended that we use the optional binding method discussed next instead of force unwrapping.
We use optional binding to check whether an optional variable or constant has a valid (non-nil) value, and, if so, assign that value to a temporary variable. For optional binding, we use the if let
keywords together. The following code illustrates how optional binding is used:
if let temp = myOptional { println(temp) println("Can not use temp outside of the if bracket") } else { println("myOptional was nil") }
In the preceding example, we use the if let
keywords to check whether the myOptional
variable is nil. If it is not nil, then we assign the value to the temp
variable and execute the code between the brackets. If the myOptional
variable is nil, we execute the code in the else
bracket, which prints out the message myOptional was nil
. One thing to note is that the temp
variable is scoped only for the conditional block and cannot be used outside of the conditional block.
Optional chaining allows us to call properties, methods, and subscripts on an optional that might be nil. If the optional or any of the chained values return nil, the return value will be nil. The following code gives an example of optional chaining using a fictitious car
object. In the example, if either car
or tires
are nil, then the variable s
will be nil; otherwise, s
will equal the tireSize
property;
var s = car?.tires?.tireSize
The following Playground illustrates the three ways to verify whether the optionals contain a valid value prior to using them:
In the preceding Playground, we begin by defining the optional string variable stringOne
. We then explicitly check for nil by using the !=
operator. If stringOne
is not equal to nil, we print the value of stringOne
to the console. If stringOne
is nil, then we print the Explicit Check: stringOne is nil
message to the console. As we can see in the results console, Explicit Check: stringOne is nil
is printed to the console because we have not assigned a value to stringOne
yet.
We then use optional binding to verify that stringOne
is not nil. If stringOne
is not nil, then the value of stringOne
is put into the tmp
temporary variable and we print the value of tmp
to the console. If stringOne
is nil, then we print the message Optional Binding: stringOne is nil
to the console. As we can see in the results console, Optional Binding: stringOne is nil
is printed to the console because we have not assigned a value to stringOne
yet.
We use optional chaining to assign the value of the lastPathComponent
property of the stringOne
variable to the pathString
variable if stringOne
is not nil. As we can see, the pathString
variable is nil because we have not assigned a value to stringOne
yet.
We then assign a value of http://www.packtpub.com/all
to the pathString
variable and rerun all three tests again. This time pathString
has a non-nil value; therefore, the value of pathString
or the lastPathComponent
property is printed out to the console.
Note
It is tempting to say that I may need to set this variable to nil, so let me define it as optional but that would be a mistake. The mindset for optionals should be to only use them if there is a specific reason for the variable to have nil value.