Mastering Swift
上QQ阅读APP看书,第一时间看更新

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.