Introducing optional types in Swift iOS 20.08.2018

When we declare variables in Swift, they are by default non-optional, which means that they must contain a valid, non-nil value. If we try to set a non-optional variable to nil, it will result in an error.

For example, the following code will throw an error when we attempt to set the message variable to nil because it is a non-optional type:

var message: String = "My String"
message = nil

A variable defined as an optional can contain a valid value or it can indicate the absence of a value. We indicate the absence of a value by assigning it a special nil value. Optionals of any type can be set to nil, whereas in Objective-C, only objects can be set to nil.

To really understand the concept behind optionals, let's look at a line of code that defines an optional:

var myString: String?

The question mark at the end indicates that the myString variable is an optional. We read this line of code as saying that the myString variable is an optional type, which may contain a value of the string type or may contain no value. The subtle difference between the two lines actually makes a big difference in understanding how optionals work.

Optionals are a special type in Swift. When we defined the myString variable, we actually defined it as an optional type. To understand this, let's look at some more code:

var myString1: String?
var myString2: Optional<String>

These two declarations are equivalent. Both lines declare an optional type that may contain a string type or may lack a value. In Swift, we can think of the absence of a value as being set to nil.

The optional type is an enumeration with two possible values, None and Some(T), where T is the generic associated value of the appropriate type. If we set the optional to nil, then it will have a value of None, and if we set a value, then the optional will have a value of Some with an associated value of the appropriate type

Internally, an optional is defined as follows:

enum Optional<T> {
    case None
    case Some(T)
}

Here, T is the type to associate with the optional.

The key to using optionals is to always verify that they contain a valid value prior to accessing them. We use the term unwrapping to refer to the process of retrieving a value from an optional.

To unwrap or retrieve the value of an optional, we place an exclamation mark (!) after the variable name. This is called forced unwrapping. Forced unwrapping, in this manner, is very dangerous and should be used only if we are certain that the variable contains a non-nil value. Otherwise, if it does contain a nil value, we will get a runtime error and the application will crash.

When we use the exclamation point to unwrap an optional, we are telling the compiler that we know the optional contains a value, so go ahead and give it to us. Let's look at how to do this:

var myString1: String?
myString1 = "test"
var test: String = myString1!

We should verify that the myString1 optional; contains a valid value prior to unwrapping it. The following example is one way to do this:

var myString1: String?
myString1 = "test"
if myString1 != nil {
    var test = myString1!
}

Unwrapping optionals is not the optimal way, and it is not recommended that we unwrap optionals in this manner. We can combine verification and unwrapping in one step, called optional binding. Optional binding is the recommended way to unwrap an optional. With optional binding, we perform a check to see whether the optional contains a valid value and, if so, unwrap it into a temporary variable or constant. This is all performed in one step.

Optional binding is performed with the if or while conditional statements. It takes the following format if we want to put the value of the optional in a constant:

if let constantName = optional {
    statements
}

The following example shows how to perform optional binding:

var myString3: String?
myString3 = "Space"
if let tempVar = myString3 {
    print(tempVar)
} else {
    print("No value")
}

One thing to note is that the temporary variable is scoped only for the conditional block and cannot be used outside it.

We can use the guard statement with optional binding to verify that an optional has a valid value. The following example illustrates this:

func sayHello(name: String?) {
    guard let internalName = name else {
        print("Name has not value")
        return
    }
    print("Hello \(internalName)")
}

In the sayHello(name:) function, we use the guard statement to verify that the name parameter contains a valid value, and if not, we print out the message Name has no value. If the name parameter does have a valid value, we then print out a hello message. The one thing to note from this example is that the internalName constant is scoped for the function; therefore, we can use it throughout the function.

The nil coalescing operator is similar to the ternary operator. The ternary operator assigns a value to a variable, based on the evaluation of a comparison operator or a Boolean value. The nil coalescing operator attempts to unwrap an optional, and if it contains a value, it will return that value, or a default value if the optional is nil.

Let's look at a prototype for the nil coalescing operator:

optionalA ?? defaultValue

In this example, we demonstrate the nil coalescing operator when the optional contains a nil and also when it contains a value:

var defaultName = "Jon"
var optionalA: String?
var optionalB: String?
optionalB = "Buddy"
var nameA = optionalA ?? defaultName
var nameB = optionalB ?? defaultName

The nil coalescing operator is shorthand for using the ternary operator as follows:

var nameC = optionalA != nil ? optionalA! :defaultName