Wrap your head around optionals in Swift

Since you’re pretty much required to use optionals in Swift, you need to know how they work if you want to understand Swift. But if you’re like most developers who are new to Swift, you might still be having a little trouble with them. Or a lot. So read on to learn about what they are, how to declare and unwrap them, how to use the nil coalescing operator, and how to use optional binding to make your Swift code safer and more concise.

What is an optional?

Let’s start by looking at what an optional is. From The Swift Programming Language:

Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”.

Pretty simple, right? So an optional is something – a property, local variable, method parameter, etc. – that either has a value, or it’s nil (it has no value). In fact, the only way something can be nil in Swift is if it’s optional. That means that if something’s not declared as optional, it’s not nil.

(You should read the entire section on optionals from The Swift Programming Language for a fuller explanation.)

Declaring a type as optional with ?

OK, so an optional is a type that may be nil. Unlike in Objective-C, where any object can be nil, in Swift, only types that are marked as optional can be nil.

We can mark types as optional with a question mark (?). Check out the movies property in the ViewModel:

var movies: [NSDictionary]?

So movies is declared as an optional array of NSDictionary objects. This means that movies is either an array containing NSDictionary objects, or it’s nil. And for now, since we haven’t set movies to a value, it is nil. Later, we can set it to some value – some array of NSDictionary objects – and even set it back to nil, if we’d like.

Accessing properties with optional chaining

When we have a type declared as optional with the ?, we can access it (and its properties) using the question mark operator (?), known as optional chaining. We did this in our ViewModel, in numberOfItemsInSection:

movies?.count

Here, we’re saying that we’d like the count of movies, please. But since movies is an optional, we need to acknowledge that we know it may be nil by using the question mark. So Swift’s compiler forces us to remember that we’re dealing with an optional type – unlike Objective-C, which couldn’t care less at compile time whether an object is nil.

For more on optional chaining, there’s an entire section on it in The Swift Programming Language.

The nil coalescing operator: ??

While we’re looking at numberOfItemsInSection, let’s take a look at another operator that may be a bit confusing. This one:

??

In Swift, we call this the nil coalescing operator. In other languages, it’s sometimes called the null coalescing operator, Logical Defined-Or operator, or the Elvis-operator.

Let’s look at our code in the ViewModel again:

func numberOfItemsInSection(section: Int) -> Int {
    return movies?.count ?? 0
}

This is saying that if movies is not nil, then return the count of the movies array. And if it is nil (meaning movies?.count will also be nil, per optional chaining), then return 0. So the nil coalescing operator allows us to easily return a default value when the property we’re using is nil.

Declaring an implicitly unwrapped optional with !

In our ViewModel, we declared our moviesClient property like this:

@IBOutlet var moviesClient: MoviesClient!

This is an optional too, but it’s a bit different from optionals declared with a ?. With this one, we’re saying that while moviesClient is optional and may be nil, we know that it won’t be nil when we’re ready to use it. This is called an implicitly unwrapped optional. (Again, you should read the entire section on optionals from The Swift Programming Language for a fuller explanation.)

Now, if we fail to set moviesClient to a value, the app will crash when we try to access it. But declaring optionals as implicitly unwrapped has its advantages…

We can use moviesClient without putting a question mark after it, like this:

moviesClient.fetchMovies { //...

And that makes our code a bit more readable than the alternative – having question marks all over the place. So an implicitly unwrapped optional makes it a bit easer to access the value later on. But they are dangerous and can cause crashes, so I’d recommend using them sparingly. I generally use them just for IBOutlets, since I know those will be set through the Storyboard, and therefore won’t be nil.

Optional binding with if let

Another way to unwrap the value from an optional is with the if let syntax, known as optional binding. It’s a common pattern in Swift, and it’s my preferred method for getting the value out of an optional.

In MoviesClient, we parsed our JSON using optional binding. Here’s an example from fetchMovies:

if let movies = json.valueForKeyPath("feed.entry") as? [NSDictionary] {
    completion(movies)
    return
}

Let’s focus just on the first line. Here’s what it’s saying: if json.valueForKeyPath("feed.entry") returns a value, and if we can turn that into an array of NSDictionary, then create a constant called movies and assign that array to it. That’s a mouthful, a brainful, and it might be easier to understand by breaking it apart. We could, instead, do something like this:

let movies = json.valueForKeyPath("feed.entry") as? [NSDictionary]
if movies != nil {
    completion(movies)
    return
}

So here, we’re saying that we want to create an array of NSDictionary objects from the JSON at “feed.entry” and set it to the movies constant. That movies array may be nil, or it may not. If it’s not nil, the completion closure will run, and we’ll return from the method.

This is almost identical to the if let above. The main difference is that in the second example here, movies is always created and available in the broader scope, whereas in the first example, movies is only created and accessible inside the if block when our JSON parsing and casting returns a non-nil value.

I hope this answers your questions about optionals and gives you a better understanding of how they work in Swift.

Learn Swift with the 5-Part Guide to Getting Started with Swift – and never worry about whether you’ll be stuck maintaining legacy Java for the rest of your life.