Faryar Fathi

Composer, Coder, Entrepreneur

A Look at Swift Optionals

In programming, there are times that you need to represent the concept of no value. Take a form field for example where you ask users to enter their age. Assuming that response represents the entered text, you can use the toInt() method of the String class to store the user’s age in a constant:

1
let age = response.toInt()

When response has an integer representation, say “32” for example, toInt() returns a value, but what if the user entered something like “None of your business”? In cases like this, we need some way to represent no value.

Objective-C uses nil and NSNotFound to represent the concept of no value; Swift uses optionals.

An optional is Swift’s way of saying: there might be Some value or there might be None.

To mark a value as optional, we add a question mark (?) after the type of the value.

Here’s an example:

1
var age: Int?

Here, age might contain some integer or might contain no value.

As an aside, you can specify a variable has no value by assigning it nil. Optional variables or constants that are defined without default values are automatically set to nil. In the above example, the value of age is nil.

Using Optionals

Since an optional might return nil, we want to check if it contains any value before using it. This can be done by comparing it against nil.

1
2
3
4
5
var firstName: String? = "John"

if firstName != nil {
println("firstName has some String value!")
}

We now know that firstName does in fact contain some value, but if you try using it in println(), the result might surprise you.

1
2
3
if firstName != nil {
println("Hello, \(firstName)") // prints Hello Optional("John")
}

And this brings us to something that might be confusing at first, so read the next paragraph carefully.

A string optional declaration doesn’t mean your variable contains either no value or a string. It means that your variable either contains no value or it contains an optional of type String.

A look at the Swift header file makes this more clear.

1
2
3
4
5
enum Optional<T> {
    case None
    case Some(T)
    // ...
}

As you can see, an optional is its own type, an enum in fact, that can return either None or Some(T), where T is an associated value of the correct type.

Therefore, before using an optional, you need to first access its underlying value.

Before moving any further, let’s take a look inside our firstName variable and see what’s going on at a lower level using fr v -R in LLDB:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(Swift.Optional<Swift.String>) firstName = Some {
  Some = {
    _core = {
      _baseAddress = {
        value = 0x000000010ab936a0 "John"
      }
      _countAndFlags = {
        value = 4
      }
      _owner = None {
        Some = {
          instance_type = 0x0000000000000000
        }
      }
    }
  }
}

Compare this with the case where firstName has no value (is nil):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(Swift.Optional<Swift.String>) firstName = None {
  Some = {
    _core = {
      _baseAddress = {
        value = 0x0000000000000000
      }
      _countAndFlags = {
        value = 0
      }
      _owner = None {
        Some = {
          instance_type = 0x0000000000000000
        }
      }
    }
  }
}

This is quite complicated, but still easy enough to see how the compiler handles the Some and None cases and keeps track of the underlying value.

Unwrapping Optionals

The are two ways to access the underlying value of an optional: forced unwrapping and optional binding.

Forced unwrapping

If you are certain that an optional contains a value, you can access the underlying value by force unwrapping the optional. This is done by adding an exclamation mark to the end of the optional’s name.

Going back to our previous example, we can now access the String value in firstName:

1
2
if firstName != nil {
println("Hello, \(firstName!)") // prints Hello John

Warning: if you try to force-unwrap an optional that contains no value, you’ll get a runtime error and your app crashes.

By using forced unwrapping, you are promising the compiler that the optional will have a value at runtime, and it can be unwrapped. You better make good on that promise if you don’t want a crash on your hands!

Optional binding

Optional binding is a rather elegant way of unwrapping an optional with the help of a temporary constant or variable.

The syntax is like this:

1
2
3
if let actualValue = someOptional {
  // do something with the actualValue
}

Here, the compiler checks someOptional to see if it contains a value or not. If there’s a value, it will be assigned to the temporary constant actualValue, which can be used inside the if block.

You can also use an else statement to handle the case where someOptional contains no value.

Let’s use optional binding to unwrap the value of our firstName variable:

1
2
3
4
5
6
7
if let firstNameValue = firstName {
  println("Hello, \(firstNameValue)")
} else {
  println("firstName contains no value!")
}

// prints: Hello, John

Implicitly Unwrapped Optionals

Often the only time an optional has no value when it’s first defined. In other words, you know that after the value is initially set, the optional always has a value.

Implicitly unwrapping an optional allows you to use its underlying value, without having to nil-check or unwrap it.

An implicitly unwrapped optional is declared by placing an exclamation mark after the type (instead of a question mark).

1
var buttonWidth: CGFloat!

Implicitly unwrapping an optional is the equivalent of asking the optional to automatically unwrap itself each time it is used. For example, you can use buttonWidth from the above example, like a normal variable without having to unwrap its value first.

Of course, if your assumption is false, and the optional is nil at some point, you’ll have a runtime error.

Let take a look at an example:

1
2
3
4
5
6
7
8
 class MyView : UIView {
    @IBOutlet var button : UIButton!
    var buttonWidth : CGFloat!

    override func awakeFromNib() {
        self.buttonWidth = self.button.frame.size.width
    }
}

Here, you know that by the time that awakeFromNib() is called, all the outlets are guaranteed to have been configured. So, it’s perfectly safe to use button in awakeFromNib() or viewDidLoad() without worrying about it returning nil. And this is why we declare it as an implicitly unwrapped optional.

While we are on this topic, Apple recommends using implicitly unwrapped optionals for outlets:

When you declare an outlet in Swift, you should make the type of the outlet an implicitly unwrapped optional. This way, you can let the storyboard connect the outlets at runtime, after initialization. When your class is initialized from a storyboard or xib file, you can assume that the outlet has been connected.

Excerpt from Using Swift with Cocoa and Objective-C

Nil Coalescing Operator

If you are a fan of ternary conditional operator like yours truly, you gonna like this one, despite the somewhat funky name!

Nil coalescing operator allows you to unwrap an optional if it has a value, or use a default value if the optional is nil. The syntax is:

Note: Unfortunately I cannot use ⁇ in code blocks, so there is an extra space between the questions marks in the following blocks. There is no space between question marks in the nil coalescing operator.

1
optional ? ? defaultValue

And similar to ternary operator, nil coalescing operator is usually used in assignments:

1
var myVariable = optional ? ? defaultValue

Let’s look at an example:

1
2
3
4
var defaultColorTheme: String = "defaultTheme"
var userColorTheme: String?

var colorTheme = userColorTheme ? ? defaultColorTheme

Here, if our user has already selected a colour theme and userColorTheme has a value, it will be unwrapped and assigned to colorTheme. If userColorTheme is nil on the other hand, the defaultColorTheme will be assigned to colorTheme.

Optional Chaining

Optional chaining is a mechanism for querying optionals. It is specially useful when dealing with nested optionals in classes or structs. Consider the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct RentalUnit {
  let unitNumer: Int
  let occupant: Renter?
  // ...
}

struct Renter {
  let name: String
  let guarantor: Person?
  // ..
}

struct Person {
  let name: String
  let creditScore: Int?
  // ..
}

One way to check the guarantor’s credit score for a rental unit is using implicitly unwrapped optionals:

1
let guarantorCreditScore = rentalUnit.occupant!.guarantor!.creditScore!

The problem with this approach is if a rental unit has no guarantor, or if the guarantor doesn’t have a credit score, we’ll end up with a runtime error!

Nested if let statements don’t make a very elegant solution either:

1
2
3
4
if let myOccupant = rentalUnit.occupant {
  if let theGuarantor = myOccupant.guarantor {
      if let creditScoreValue = theGuarantor.creditScore {
        // do something

Optional chaining is the answer in such cases. The syntax is similar to that of implicitly unwrapped optionals. All you need to do is to replace the exclamation marks (!) with question marks (?):

1
2
if let guarantorCreditScore = rentalUnit.occupant?.guarantor?.creditScore? {
  // do something 

Here, the links in the chain are checked sequentially. For each link, if there’s a value, it will be unwrapped and the process continues to the next link. If it there’s no value, nil is returned and the entire chain fails gracefully.

Important: The result of an optional chaining call is always an optional value, even when the query returns a non-optional value.

Let’s take a look at an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person {
  var education: Degree?
  // ...
}

class Degree {
  var university = "Concordia University"
  //..
}

let john = Person()
john.education = Degree()

println(john.education?.university)
// prints Optional("Concordia University")

Here, regardless of the fact that university is a non-optional String, since we accessed it with optional chaining, a String? is returned. Therefore, we need to first unwrap the optional String before using its value:

1
2
3
4
5
6
if let university = john.education?.university {
  println("John attended \(university).")
} else {
  println("Unable to find a university!")
}
// prints John attended Concordia University.

References:

  1. Swift Programming Language
  2. Using Swift with Cocoa and Objective-C
  3. Intermediate Swift
  4. Why create “Implicitly Unwrapped Optionals”?
  5. Advanced Swift Debugging in LLDB