A Practical Guide For Handling Optionals

So there you are. New to Swift and trying to wrap your head around the so-called optionals. Speaking of "wrapping", let's take a closer look at this wrapper-type and unwrap this feature of the programming language.

Written by 

You may get confused when looking at Swift example code for the first time and noticing all the "?" and "!" you find in the code. It's a concept that's keeps your application more safe from crashing if done correctly. Also, you'll be using it a lot so let us take a deeper dive into it.

Optionals overview

So what we're dealing with is a feature in Swift which we call optionals. It's allows the compiler to warn you whenever you're simply assuming a variable to have a value but in reality it might be nil (empty). In Javascript, for instance, you may have a variable that you expect to have a value but forget to check the possibility that it doesn't. Only runtime checks will determine if a value might be nil.

This is where optionals in Swift become very powerful. They ensure compile time checks as they simply exist as a type in the type system. Yes, just like we have Int representing an integer, we also have the Int? which is an optional integer. Because of this type, the compiler is able to verify safety and determine when nil must be considered or not.

Think of an optional as a wrapper. They wrap around the content of a variable. And first by unwrapping the optional, we'll find out if the variable is nil or have a value. We define an optional this way:

let myOptional: Int? = nil

The optional above doesn't have a value as we initialised it with nil but later on, we might reassign it. At one point, we need to access the value inside the optional. This action is also known as "unwrapping" the optional. It can be done in various ways which we'll take a look at now.

Force unwrapping

The first way of accessing the value inside an optional is force unwrapping using the "!" operator but it's very often a bad idea to use this approach. In code, it looks like this:

In the example above, we are absolutely sure that the optional contains a value. But in other cases, there might be a chance where nil is found inside the optional. That will lead to a crash inside our application. There are much safer methods of accessing the value and to avoid a crash. One method for this purpose is called optional binding.

Optional binding using if let

Now, let's look at the optional binding syntax using if let that is much safer than using force unwrapping.

In the example above, we only access the value inside the variable as long as it contains a value which we check using the if let statement. This way we avoid any horrible crashes caused by handling the optional unsafely. It's also possible to unwrap multiple optionals inside the same if-statement using the following syntax as seen in the following code:

In some cases, you may find your code having a pyramid-structure with a lot of indentation using if let inside if let. The approach above of unwrapping multiple optionals can become useful to avoid the pyramid-shape on a smaller scale. But there's another way of doing optional binding to completely eliminate that issue using guard let.

Optional binding using guard let

This is a more preferred style of optional binding using guard let to avoid the pyramid that occurs from using if let statements. Take a look at the example code below:

As you can see, it's simply a different way of doing optional binding. We even avoid the indentation that comes from write our code inside a new if let statement, every time we unwrap an optional.

Nil coalescing

Sometimes we simply want a default value when the optional turns out to be nil. This can easily be achieved by using the following approach.

We can see that the special "??" operator comes to the rescue. It's a useful trick known as nil coalescing that is very easy to implement in your code. It simply translates to "if the optional is nil, then use zero as the value. If not, use the unwrapped value.

Optional chaining

I've got one last trick for you. It's a useful feature called optional chaining that allows you to call any methods or properties on an optional that may or may not be nil. Let's look at the following example:

So in this specific example, we are instantiating the struct Computer which has an optional property processor of the type Processor. This optional property contains the integer property modelNumber. When we decide to access the modelNumber, we use the "?" operator right after our optional property processor (line 17). That way we ask beforehand if the optional processor contains a value, and if so, access the modelNumber.

One thing to note about optional chaining is that the result of optional chaining is always an optional. For this reason it makes sense to unwrap it on the same line using optional binding.

Wrapping up (no pun intended)

In this post, we looked at different ways of handling optionals. Hopefully they seem simple by now (or at least after a little more practice). Bookmark this blog post for now, so you can easily look up how to use them properly. I strongly encourage you to get this under your belt.

Thanks for reading. Remember to leave a comment and share with your fellow developers.

Share this post

Facebook
Twitter
LinkedIn
Reddit

You may also like

Comparison

Native App vs React Native App – What Should You Choose?

Gone are the days where the only options in mobile app development were native iOS and Android. The choices are broader nowadays, and frameworks have popped up with React Native being the most popular alternative. So what approach should you choose for your next app?

Process

Refactoring iOS Apps – A Pragmatic Guide

While your app and development teams grow larger, the codebase is inevitably going to scream for refactoring – that is, improvements in the design of the existing code. There are no silver bullets to refactoring, but iOS apps tend to get into the same pitfalls. Luckily, the common cases of refactoring can be mitigated by being in line with the following set of practices on improving and maintaining code while speeding up development.