Swift Optionals

As an Objective-C developer, the biggest point of confusion for me was with optionals. There are of course other tricky idiosyncrasies, but the hardest thing to wrap my head around was the use of optionals and what the hell “?”,”!”, and “??” means.

Why We Needed Optionals

If you are at all familiar with objective-C , then your well aware that every object had the option of returning nil. To make code safe, we had to typically check for nil all of the time. Often we would set a return nil when something went wrong as well. So we would end up with a bunch of ugly code that looked something like this:


- (NSString *)getStringItemFromResponse:(id)responseObject {
    if([responseObject] != nil && [responseObject isKindOfClass:[NSDictionary class]]){                        
        return responseObject[@"someItem"];

    }

    return nil;
}

Notice that we return nil here if we fail to return a string by the end. Also notice that I purposely left out a check to ensure that responseObject[@”someItem”] is not nil and it is actually an NSString. Although we try to be perfect, most of us forget to do this sort of check from time to time. Swift can help with this.

How Can Swift Help?

When you define something as optional in swift, for instance the return would be a string optional, we’re saying this will either be a string or nil. This means, swift will force you to handle the condition where responseObject[@”someItem”] may be nil.

Now let’s consider a swift example of somewhat similar code:


func getStringFromResponse(responseObject:Any?) -> String? {

    if let tmpResponse = responseObject as? [String:String] {

        return tmpResponse["someItem"]
    }

    return nil
}

Here we’ve created a method that can take any object as an optional and it will return a string optional. Also, notice with swift you can declare a variable within the if statement. This is called optional binding. This variable will be a non-optional result inside if statement if evaluates to true. This result can then be used inside of the if statement.

First we can take the any object and make a variable within an if statement to check if the response object is a dictionary that contains only a string key and a string value. If that is true, we will return tmpResponse[“someItem”], which will return only a string value because our check. If none of that passes the if statement we’ll return nil. For this method to pass, you’ll have to make sure your dictionary type is [String:String]. This is a little more elegant and easy to read than the last response, but more importantly, all nil conditions and proper return types are guaranteed.

This example works if we expect the anyObject dictionary that comes in to have the type [String:String]. But what if the dictionary contains any object or primitive with a string key? For example [String:Any]

Well swift will let us handle that too!


func getStringFromResponse(responseObject:Any?) -> String? {

    if let tmpResponse = responseObject as? [String:Any]{

        return tmpResponse["someItem"] as? String
    }

    return nil
}

Or equivalently, and perhaps a little better:


func getStringFromResponse(responseObject:Any?) -> String? {

    if let tmpResponse = responseObject as? [String:Any],
        let tmpResult = tmpResponse["someItem"] as? String{

        return tmpResult
    }

    return nil
}

A Little More on Optional Chaining and Optional Binding

In the previous examples, you saw the use of optional binding in the if statements.

In Objective-C if you tried to operate on variable with a nil value, then you would crash. For example:


UILabel *someLabel = nil;
UILabel.text = @"Some Text"  //< -- Insta Crash :(

In Swift however, this it totally good if you define the label as an optional.


let someLabel: UILabel? = nil < -- the question mark makes it an optional.
someLabel?.text = "Some Text" < -- If nil, the text setter wont ever be attempted.

You can also keep chaining these


let someView: UIView? = nil
let cgColor = someView?.tintColor?.CGColor < -- cgcolor will be nil

So in this last example if someView is not nil, but tintColor is nil, then CGColor doesn’t get attempted. Swift is super safe (If done right :]).

From the cgColor example, if all you want is cgColor then you can use the optional chaining method we used. However, if you plan on accessing multiple elements of an optional, its better to use optional binding like so:


if let view = someView, let color = view.tintColor {

    print(view.description)
    print(color.description)

}

Here I’m not doing anything with the values, but you can see how optional binding is safe and helpful. If view evaluates to a non-nil value and color (which is derived from that previous value) is also non nil; than this if function will proceed. You can easily access each of the variables that have guaranteed values.

WTF is This “!” For?!!?

When working with optionals, you’ll probably make some mistakes and the compiler will suggest placing an exclamation point next to your optional. This is typically a bad idea. The exclamation point force unwraps the optional, and basically removes the optional protection. You’re basically saying, “It’s all good! This variable definitely is not nil”. Remember that Objective-C example with the nil label? Well this is basically the same thing. Just to be thorough though:


let someView: UIView? = nil
let color = someView!.tintColor < -- Insta Crash :(

For the most part, don’t use em. You can almost always use optional binding instead.

The main exception is when you define a class variable that is a foundation framework type (eg. UIButton, UIView, NSDate) without an initial value. These typically get defined as:


@IBOutlet var mainButton: UIButton!

This is because you are bridging over an Objective-C type. nil in swift is different from Objective-C, in Objective-C nil is a pointer to a nonexistent object. In swift, nil is not a pointer but rather the absence of a value. In other words, an Objective-C object always has a value and that value is a pointer. That value may be a pointer to a valid object, or a pointer to a nil object. So we implicitly unwrap it so we aren’t constantly having to unwrap it every time we use it. This would be super annoying. Implicitly unwrapping bridged Objetive-C elements is a compromise to make our lives easier. Take note though, you will still need to initialize these before using them.

Final Thoughts

When I first saw optionals, I didn’t care much for them. They seem to be a hassle, but once you take the time to really understand them, they actually turn out to be a time saver. Not to mention I have noticed most classes have substantially less lines without all the checking to make sure a value is not nil.

About Joe Hoffman

I am An Electrical Engineer that spends a lot of my off time doing web development and other programming. Currently I am trying to expand my knowledge with iOS and I find that writing tutorials helps me learn more thoroughly as well as provide some useful info to others.

Speak Your Mind

*

css.php
Privacy Policy