Why you should avoid force unwrapping in Swift
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 with Optional
contributes greatly to its safety. Can you imagine having a language where you don't know whether something could be nil
? Well... languages like Objective-C and Java required developers to constantly check for null
or nil
values to prevent crashes.
I'm sure you can imagine that this would go wrong all the time and if you Google for a term like null pointer exception you'll hit loads of results.
Null pointer exceptions are a class or errors that Swift has completely eliminated by having Optional
as a type. So let's dig into Optional
a bit, and see why that tempting !
operator is so dangerous, shall we?
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?
or var episeodeName: Optional<String>
(these are equivalent; the former is syntactic sugar for the latter).
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 the value might be nil
after initialization but 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
if let episodeName {
println(episodeName) // prints episodeName's value
}
// or guard...
guard let episodeName else {
// episodeName is nil
return
}
print(episodeName)
However, if you're 100% sure you've set a value, you can tell the Swift compiler that you don't want to explicitly unwrap your value because you know what you're doing and you just want to get your episode’s name by forcing an unwrap:
println(episodeName!)
By adding the exclamation mark after episodeName
, we force unwrap it and we can use it's value straight away without an extra if
or guard
statement. Sounds great, right?
Well.. not quite!
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 crash when we run it. 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.
But then your project matures...
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 at your desk "What's going on" they ask. 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 crash 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 episodeName {
println(episodeName)
} 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.
In Summary
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
or guard 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.