The dangers of forcefully unwrapping values

Published on: July 13, 2015

Whenever I'm programming, I have a goal in mind, generally a problem to solve. I want my solutions to be simple, yet elegant and reliable. Thankfully, Swift is a great language for this. The language is safe, its syntax is beautiful with great readability. The way Swift handles nullability contributes greatly to its safety.

If you want to declare a variable in Swift you can use either the let or var keyword. If you don't want to assign a value to one of your properties right away you could write something like var episodeName: String?. This informs the Swift compiler that episodeName might not have a value when we're accessing it. If we don't add the question mark and write var episodeName: String, the episodeName will need to be assigned a value when we initialize the object that contains this property. A third way to declare episodeName is to implicitly unwrap the value: var episodeName: String!. This tells the compiler that we are 100% sure that episodeName will get a value before we attempt to access it.

These question mark / exclamation mark semantics also apply to using variables in your code. When you've declared your variable with a questionmark (var episodeName: String?) we are never sure if episodeName is nil or a String. So whenever we want to use this variable we need to unwrap it. The safest way to do this is as follows:

if let name = episodeName {
    println(name) // prints episodeName's value
}

However, if you're 100% sure you've set a value, you can tell the Swift compiler to stop complaining because you know what you're doing and you just want to get your episode’s name:

println(episodeName!)

By adding the exclamation mark after episodeName, we force unwrapping it and we can use it's value straight away without an extra if statement.

Where's the danger?

If you're writing an application you're sometimes sure that you assign a value to something. For example, you might have written something like:

var show = TVShow()
show.episodeName = apiData.name
show.printEpisodeName()

This code should usually be safe. Before we ask the show for it's episodeName we actually set it so we're always sure that episodeName has a value before we access it. So the implementation of printEpisodeName might be:

func printEpisodeName() {
    println(episodeName!)
}

This shouldn’t throw errors. After all, we know what we're doing! We always set the episodeName right after we instantiate our class. What could go wrong, right? Well... besides the fact that we probably should have created an initializer that takes the episodeName, a lot can go wrong.

Honeymoon's over..

So, our project has been ongoing for a few weeks and we're changing the API. Before, we were guaranteed that the API would always return properly formatted JSON but we've decided that things like the name for an episode isn't guaranteed anymore. In other words, the name can be nil.
We test our app, everything still works when we're navigation to our show page so we're happy. But then.. crash reports come in. Users are livid and to add insult to injury, your manager is suddenly next to your desk. The app is crashing. Hard.

What's going on!? Everything was fine before! So we start searching and debugging. And once we manage to reproduce the error we see what's going on:

Unexpectedly found nil while unwrapping an optional value

And then we remember. The forcefully unwrapped optional in our TVShow class:

func printEpisodeName() {
    println(episodeName!)
}

When we set the episodeName on our tv show, the name we get from the API can be nil. And that's alright because we declared our episodeName like this: var episodeName: String?. Which means that episodeName can be either nil or a String. Luckily, our bug is easily fixed:

func printEpisodeName() {
    if let name = episodeName {
        println(name)
    } else {
        println("model id is nil")
    }
}

Now we handle the optional value properly, we avoid crashes and an angry manager. Time to get yourself a cup of coffee and tell your manager that you've fixed the error.

The takeaway 🙂

As we saw in this post it can be tempting to force the unwrappin of a variable when we're pretty sure that we will set it before we use it. But as requirements change it can be easy to overlook situations where a variable can suddenly be nil when we try to access it.

My advice is to (almost) always unwrap optionals properly with an if let construction. It's the only way to be 100% sure that you're not accidentally accessing a variable whose value is actually nil. More importantly, this will help to prevent future crashes.

So remember kids, always unwrap your optionals in a safe way.

Categories

Swift

Subscribe to my newsletter