inaka

Latest blog entries

/
The Art of Writing a Blogpost

The Art of Writing a Blogpost

Apr 11 2017 : Matias Vera

/
SpellingCI: No more spelling mistakes in your markdown flies!

Feb 14 2017 : Felipe Ripoll

/
Fast reverse geocoding with offline-geocoder

Do you need a blazing fast reverse geocoder? Enter offline-geocoder!

Jan 18 2017 : Roberto Romero

/
Using Jayme to connect to the new MongooseIM REST services

MongooseIM has RESTful services!! Here I show how you can use them in an iOS application.

Dec 13 2016 : Sergio Abraham

/
20 Questions, or Maybe a Few More

20 Questions, or Maybe a Few More

Nov 16 2016 : Stephanie Goldner

/
The Power of Meeting People

Because conferences and meetups are not just about the technical stuff.

Nov 01 2016 : Pablo Villar

/
Finding the right partner for your app build

Sharing some light on how it is to partner with us.

Oct 27 2016 : Inaka

/
Just Play my Sound

How to easily play a sound in Android

Oct 25 2016 : Giaquinta Emiliano

/
Opening our Guidelines to the World

We're publishing our work guidelines for the world to see.

Oct 13 2016 : Brujo Benavides

/
Using NIFs: the easy way

Using niffy to simplify working with NIFs on Erlang

Oct 05 2016 : Hernan Rivas Acosta

/
Function Naming In Swift 3

How to write clear function signatures, yet expressive, while following Swift 3 API design guidelines.

Sep 16 2016 : Pablo Villar

/
Jenkins automated tests for Rails

How to automatically trigger rails tests with a Jenkins job

Sep 14 2016 : Demian Sciessere

/
Erlang REST Server Stack

A description of our usual stack for building REST servers in Erlang

Sep 06 2016 : Brujo Benavides

/
Replacing JSON when talking to Erlang

Using Erlang's External Term Format

Aug 17 2016 : Hernan Rivas Acosta

/
Gadget + Lewis = Android Lint CI

Integrating our Android linter with Github's pull requests

Aug 04 2016 : Fernando Ramirez and Euen Lopez

/
Passwordless login with phoenix

Introducing how to implement passwordless login with phoenix framework

Jul 27 2016 : Thiago Borges

/
Beam Olympics

Our newest game to test your Beam Skills

Jul 14 2016 : Brujo Benavides

/
Otec

Three Open Source Projects, one App

Jun 28 2016 : Andrés Gerace

/
CredoCI

Running credo checks for elixir code on your github pull requests

Jun 16 2016 : Alejandro Mataloni

/
Thoughts on rebar3

Thoughts on rebar3

Jun 08 2016 : Hernán Rivas Acosta

/
See all Inaka's blog posts >>

/
Dealing with Optionals in ViewControllers

A photo of Pablo Villar wrote this on December 18, 2015 under inaka, ios, optionals, swift, viewcontroller .

Optional types in Swift are very useful, but they can become tricky sometimes.

Knowing when, how and why you should declare Something or Something? or Something! is essential to help your code reflect the business rules better and, therefore, guide its intention towards clearness.

This post is going to cover the basics about when to use each of those three declaration types in two common iOS scenarios: Model Objects and ViewControllers.

I will focus entirely on how optionals should be declared, not on how they should be used in your code. I'm assuming that you already know the basics on how they work; but, in case you don't, I suggest you to take a look here before reading on.

Optionals in Model Objects

Deciding whether a variable should be nullable or not is a piece of cake for model objects. It's as easy as just asking yourself "does it make sense for this property to be nil in some cases?". If the answer is yes, you'll use an optional. Otherwise, you won't.

Example:

class Person {
    var name: String            // Any person will always have a name
    var phoneNumber: String?    // A person might not have a phone number

    init(name: String) {
        self.name = name
    }

I want you to notice two important things here:

First, name variable is assigned within the class initializer. That happens because name must always have a value; otherwise, the compiler will complain that it doesn't have an initial value (you won't be able to instantiate a Person without a name). However, that's not true for phoneNumber, and that's because phoneNumber is an optional variable, which the compiler assumes to be nil if it hasn't been assigned anything.

Second, notice that by declaring phoneNumber as String? you've gained the benefit of dealing with phone numbers properly when managing a Person instance. The compiler will enforce you dividing your code's flow into two paths: One for when there's a phone number, and another one for when there isn't. This is very helpful in lots of cases; for instance, you could want to disable a 'call' button for any contact in the list that doesn't have a phone number.

That's it! You already know how to deal with variable declarations regarding model objects.

If you observe, up to here we've covered the Something and the Something? cases, but I haven't mentioned anything about implicitly unwrapped optionals yet (the Something! case). That's because when dealing with model objects, you'll rarely stumble upon cases where you need them.

Let's move on to ViewControllers, here is where it becomes tricky...

Optionals in ViewControllers

So far, so good. But there was a reason why I've decided to title this post "Dealing with Optionals in ViewControllers", and it's because I've found that it's in ViewController classes where people tend to make more mistakes when declaring optionals.

Don't worry if you have to hesitate a lot when deciding whether a variable should be Something or Something? or Something! in your ViewController. It used to happen to me too. But after almost a year of dealing with Swift, I've found out how manage it in the cleanest way possible. That's why I'm writing today: I want to share this knowledge with you, because I can ensure from my little experience that:

Optionals will improve and enrich your code if you use them the right way; but they will tear your code down if you don't deal with them properly.

By using optionals incorrectly you are potentially introducing bugs into your code. It also makes it harder to maintain. That's why I think it's so important to have a strong understanding of this topic.

So, let's go back to what concerns us and talk about why ViewControllers have a different treatment regarding optionals.

Variables that shouldn't be Optionals

Here is the main use case: You need to declare a variable in your ViewController and you know, from the business logic, that it's always going to have a value (or that, it should have a value).

Here is how you normally do it most of the times:

var isFormValidated: Bool = false
var numberOfSecondsLeft: Float = 60
var people: [Person] = [Person]()   // Empty array

And it just works! Notice that all of these variables are of type Something and they are assigned an initial value in-line (if you don't do so, your code won't compile).

However, sometimes you are not allowed to declare a variable like that because you can't determine its initial value at that point. Let's analyze an example that has lots of spices:

class UserProfileViewController: UIViewController {

var user: User
var headerView: ProfileHeaderView

// Won't compile: These variables aren't assigned an initial value.

}

Since it doesn't compile, lots of developers naively fall into the trap and make the mistake of declaring those variables as Something? to escape from the pressure of the compiler, even though one can state from the business logic that those variables are meant to always have a value. Doing so is incorrect, and believe it or not, this is one of the most common mistakes I've been seeing in lots of Pull Requests. Don't blame yourself, this happens a lot because we are too often discouraged to declare variables as Something!.

So, why is it not possible to assign a value in-line in these cases?

In order to answer that question, we should be able to make assumptions about how and when those variables are going to be assigned a value. Those assumptions will typically arise from our business logic.

In this case, our user is passed in from a previous ViewController in the navigation. Let's assume a scenario where the previous ViewController is a UserSelectionViewController which displays a list of users and when you tap on one of them, it pushes our UserProfileViewController by feeding it with the selectedUser.

Typically, you would assign the user from the outside, like:

// In UserSelectionViewController

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "ShowUserProfile" {
        if let controller = segue.destinationViewController as? ProfileViewController {
            controller.user = self.selectedUser!    // User is assigned here!
        }
    }
}

I want you to focus only on when controller.user is being assigned a value. I don't want you to worry right now about how that value is obtained and why self.selectedUser! has an ! in it. I'm going to cover that later.

If we had control over the ViewController's init, then we would do something like:

var user: User

init(user: User) {
    self.user = user
}

This way the compiler wouldn't complain, and we would make sure that the user is not optional. That's exactly what we did for model objects. However, there is no way we can pass user as a parameter in a ViewController's initializer like that. That's because of the way ViewControllers work: They are initialized for you; you only need to worry about their view's lifecycle. It's important that you understand this fact because this is what most of the issues when declaring variables in ViewControllers entails.

In order to solve this issue, we simply declare our user as an implicitly unwrapped optional, like this:

var user: User!

Here's when the Something! comes to the rescue... But, hold on. You could have thought that using implicitly unwrapped optionals was a bad thing to do. Well, don't freak out. I can assure you that in this case we won't kill any pony because we know exactly what we are doing, and we know we are doing it right.

This means that our user will still be an optional from the compiler point of view (because it can be nil), but it will be a normal variable for us since we are assuming from our business logic that it will always have a value before we actually use it.

As a consequence of choosing User! rather than User?, you won't have to perform any if let or force-unwrap before using it in your class; what's more, the compiler won't let you do so, and that's good, since this happens to meet exactly what we want to express:

  • There will always be a user.
  • This viewController can't work without a user.

In addition, if it turns out that the user hasn't been assigned (this would be a developer mistake), the execution flow will lead your app to crash immediately, instead of continuing to execute with unexpected results. As a plus, when it crashes, you will know exactly where the problem is.

Congratulations: We haven't fallen into any traps!

As weird as it may seem, this is the cleanest way to 'trick' the compiler and be able to deal with these kind of variables as if they were non-optionals.

There's one more thing that makes me feel even more confident and which indicates that this is the way to go: If you observe, that's how IBOutlets work.

@IBOutlet var tableView: UITableView!

It's worth it to talk a bit about it:

The tableView isn't known when the ViewController is initialized. It's assigned automagically when the nib file or storyboard is loaded. Every time we reference tableView from the ViewController, we assume that it has been assigned a value. That happens as long as we have linked our tableView variable with a valid reference in the Interface Builder. If we hadn't done that, we'd get the famous runtime exception: Unexpectedly found 'nil' while unwrapping an optional value. Don't panic. Crashes don't always mean evil. This kind of crash is what I call a good one, because it's letting us know that we have forgotten to do something (in this case, linking an object in the interface builder). These good crashes are usually caught in the development process and prevent bugs from being exposed to the final user.

Back to our example we still had another case to analyze:

var headerView: ProfileHeaderView       // doesn't compile

In order for the example to make sense, let's say that ProfileHeaderView's initializer needs a reference to our ViewController to work.

var headerView: ProfileHeaderView = ProfileHeaderView(delegate: self)   // doesn't compile either

The problem here is that headerView's initializer requires a reference to self, and self hasn't been initialized at that point.

However, we know that this headerView can be initialized once the viewController has been loaded. We can initialize it as follows:

var headerView: ProfileHeaderView!

override func viewDidLoad() {
    super.viewDidLoad()
    self.headerView = ProfileHeaderView(delegate: self)
}

Once again, Something! has come to the rescue. This case is even more similar to the IBOutlet one, since here we are not assigning the value from the outside, but from some place related to the view's lifecycle.

Variables that should be Optionals

We have covered the guts of the most conflictive cases of variables in ViewControllers. However, it's worth it to mention when pure optionals (Something?) have to be used...

I promised I would come back to this:

// In UserSelectionViewController

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "ShowUserProfile" {
        if let controller = segue.destinationViewController as? ProfileViewController {
            controller.user = self.selectedUser!    // User is assigned here!
        }
    }
}

Why did I have to unwrap self.selectedUser in UserSelectionViewController?

That's because that variable has been declared as a pure optional:

// In UserSelectionViewController

var selectedUser: User?

I want you to realize that it totally makes sense in this case: If you analyze it from the business logic standpoint, you won't have a user selected yet when you've arrived at this screen. In other words, selectedUser variable needs to be an optional. That's why here we haven't applied the unwrapping when declaring it but only when using it inside the prepareForSegue function, because at that point we are sure a user has been selected. That's not true for the rest of this ViewController's code, where we still have to deal with selectedUser's optionality through if lets.

Wrapping up

Honestly, I didn't want this blog post to become this long, but it makes me pretty glad that I covered most of the conflictive cases with a few simple examples.

As a little summary we can conclude that declaring a variable in a ViewController will normally fall into one of these 3 categories:

  • A. Your variable is meant to always have a value and it can be initialized in-line.
// Use: Something

var isFormValidated: Bool = false
var numberOfSecondsLeft: Float = 60
  • B. Your variable is meant to always have a value but you can't initialize it in-line.
// Use: Something!
// Make sure you initialize it properly otherwise CRASH!

var user: User!                         // B-1. Assigned from the outside
var headerView: ProfileHeaderView!      // B-2. Assigned within view's lifecycle
@IBOutlet var tableView: UITableView!   // B-3. Assigned for you behind the scenes
  • C. Your business rules indicates that it makes sense for your variable to be nil sometimes.
// Use: Something?

var selectedUser: User?

I hope I've reached you; I would love that you spread the word to your fellows, emphasizing the importance of always choosing the right Something.

See you soon and... Happy coding!

A photo of

Pablo Villar

iOS Developer