Make App Pie

Training for Developers and Artists

The Swift Swift Tutorial: Ten Points for Using Optionals.

Screenshot 2014-07-30 12.57.44In the first month and a half of using Swift, I could argue the optional value is the most difficult new concept. It isn’t hard, just something different to wrap one’s head around. That Apple’s documentation peppers information about optionals in two different e-books without consolidating the information doesn’t help. I decided to combine what I know about optionals into one post as a reference.

[edited for Swift 1.2 5/1/15]

1. You need nil so you need optionals

There are many cases where we need a state that says “this does not exist yet.” When I am deciding on breakfast for example I’m thinking about yogurt, coffee and chocolate croissants. I’m not thinking about Pizza. My choice for a pizza for lunch is not even on my mind. My choice for pizzaType is nil. The same is true in code. There are places where things just don’t exist yet, and we need a way to show it. That is what optionals are for. Optionals change any type into a type with a flag for the nil state and a value. If the optional is nil, there is no value, if the optional is non-nil there is a value.
we declare an optional like this:

var pizza:Pizza?= Pizza()

This would make an optional from the Pizza class. Swift can also do this:

var numberOfPizzas:Int? = nil

This would set an integer optional to nil. Optionals are a lot like pointers in Objective-C. However in Objective-C you can’t put a pointer to an integer, only classes. In Swift any type, not just classes, can be an optional.
When declaring optionals, if starting with nil, you can leave off the nil assignment if you wish.

var numberOfPizzas:Int?

2. Unwrap before use

Assigning to an optional is just like assigning to anything else.

numberOfPizzas = 5

However getting data from an optional is slightly more challenging. As I mentioned earlier, optional values have two parts, one for nil and one for the value. If we retrieve a value from numberOfPizzas like this:

var myNumberOfPizzas:Int =  numberOfPizzas

The result is a compiler error:

Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?

Here we need to use the force unwrap operator ! to get an integer value out of the optional

 var myNumberOfPizzas:Int =  numberOfPizzas!

The compiler error message now disappears.

3. Always check for nil

If we run now while myNumberOfPizzas is nil, we get a run time error

fatal error: Can't unwrap Optional.None

We cannot unwrap an optional that is nil. In order to prevent this, first check an optional for nil, then get its value using the force unwrap operator !

var myNumberOfPizzas:Int =  0
if numberOfPizzas != nil{
    myNumberOfPizzas = numberOfPizzas!
}

Do this for anything you make an optional. Also check a class that is optional before using the methods and properties of the class.

4. Don’t check for nil to break your code

There are times you are absolutely certain there will be a non-nil optional. If that optional is nil, something is very wrong. This is the big exception to rule #3. You want to crash the code right here, and start debugging to find out why that optional is nil. For example, when working with delegates you will have some statement that call the delegate method,

    @IBAction func saveColor(sender : UIBarButtonItem) {
            delegate!.myVCDidFinish(self, text: colorLabel!.text!)
        }

If the delegate was not set, this will crash, letting you know to go set the delegate property.

5. Implicit optionals are still optional

Although  rule 4  is an exception to  rule 3 to check for nil, it ends up there are several times we know an optional is non-nil (rule 6).  For ease of use, Swift allows you to declare a implicitly unwrapped optional. For example:

var numberOfPizzas:Int! = 1

Makes a implicitly unwrapped optional with a value of 1. Implicitly unwrapped optionals aren’t force unwrapped. Use them the same way as non-optionals, and don’t force unwrap when accessed.

myNumberOfPizzas = numberOfPizzas

In code they will look like non-optionals. It’s easy to forget that they are optionals. They are, and as optionals if they ever go nil, you will get the run time error

fatal error: Can't unwrap Optional.None

from something that doesn’t look like an optional. Just a word of caution to watch for this, especially in light of rule 6

6. Optionals are not optional for API’s

Objective C classes, as pointers, expect a nil value. As almost everything in the API’s and frameworks is an Objective-C class, almost everything you will work with is an optional. The compiler will remind you of this very often when you try to assign something to a non-optional value that is an optional value. As you check help screens and documentation you will see definitions of API like this:

func prepareForSegue(_ segue: UIStoryboardSegue!,sender sender: AnyObject!)

The definition tells you segue is an implicitly unwrapped UIStoryboardSegue and sender is a implicitly unwrapped AnyObject. For the most part, optionals in the API are implicitly unwrapped, so rule 5 above applies often when working with frameworks and API’s. Read these definitions carefully. For example, while in Swift alone you can switch around NSString and String rather easily, many places that an NSString is a property in Objective-C requires String! in Swift. For example in UILabel, the text property’s definition is:

var text: String!

The compiler will give you errors if you forget this in some situations. In some it will not…until it is too late.

7. Cast optionals down from AnyObject

What Objective-C returns as a type id, Swift returns as AnyObject!. While AnyObject! may be nice,  if you are trying to get some properties or methods from your returned object, AnyObject doesn’t work so well. Often, there is an expected subclass for the return value, such as UIButton. For example

var myButton = UIButton.buttonWithType(UIButtonType.System)

Gives the compiler warning:
Variable 'myButton' inferred to have type 'AnyObject!', which may be unexpected
If you try to use a method of UIButton, Xcode may not find any methods. Downcasting to UIButton using as! or as?

var myButton = UIButton.buttonWithType(UIButtonType.System) as! UIButton

Silences the warning, creating a non-optional UIButton. To keep consistent with Objective-c code, this is more accurate:

var myButton:UIButton! = UIButton.buttonWithType(UIButtonType.System) as? UIButton

This code produces a implicitly unwrapped optional UIButton. The as? makes myButton an optional, and the :UIButton! makes it implicitly unwrapped.

8. Chain methods not properties

Another way to unwrap an optional is to use optional chaining. For example, if  UIButton above was:

var myButton: UIButton? = UIButton.buttonWithType(UIButtonType.System) as? UIButton

It would be a basic-flavor optional. I could try this:

myButton.setTitle("Pizza", forState: UIControlState.Normal)

I would get the following error message:
'UIButton?' does not have a member named ‘setTitle'

I could force-unwrap it like this:

myButton!.setTitle("Pizza", forState: UIControlState.Normal)

If it is nil, I would get a run-time error. Another way to unwrap and check if it is nil is optional chaining like this:

myButton?.setTitle("Pizza", forState: UIControlState.Normal)

Instead of a ! we use ? The expression, if nil, does nothing. If non-nil, it calls the method. This works great for methods, but don’t use it for assigning properties of an optional class. For example, this

myButton?.tintColor = UIColor.redColor()

gives you the error:

Cannot assign to the result of this expression

You must force unwrap the value to assign it, with the risk of a run time error unless you check it. This would be best:

if myButton != nil{
myButton!.tintColor = UIColor.redColor()
}

9. Outlets are weak, weak is optional

[Edited for Xcode 6 Beta 4]
Some might argue that rule #4 applies to the last example. If myButton was strong, that would be true. However If using outlets, anything that is an outlet is weak. Prior to Xcode 6 Beta 4 If you have in your code

@IBOutlet var myButton:UIButton

and Xcode 6 beta 4 and later if you have:

@IBOutlet var myButton:UIButton!

Xcode replaces it behind the scenes with

@IBOutlet weak var myButton:UIButton! = nil

All outlets are implicitly weak optionals. Weak references are those that can be destroyed by ARC to prevent reference cycles. Weak references need to have a state of nil for when they do not have a reference so ARC can dispose of them. Thus weak references must be optionals. The weak keyword only works on optionals and classes. If you try this:

weak var myNumber = 1

The compiler will complain with a error.

'weak' cannot be applied to non-class type 'Int'

If we use a class,

weak var pizzatoo:Pizza = Pizza()

We get a different error
'weak' variable should have optional type 'Pizza?'

To use weak, have a class and an optional:

weak var pizzatoo:Pizza? = Pizza()

10. Use optional binding

In the control statements if and while the conditional statement can be replaced with an assignment of a constant. This is known as optional binding. For example:

if  let aButton = myButton{
     aButton.tintColor = UIColor.redColor()
     let type = aButton.buttonType
     let title = aButton.currentTitle
  ...
}

The constant aButton, if myButton is non-nil, executes the code with aButton used as an unwrapped myButton.  This is particularly useful if you has several things you needed unwrapped all at once. With some weak references, it is the only way you can get the values. Here’s an example from my recent post on Split View Controllers. The only way to access the outlets in the detail  view is through optional binding:

     func configureView() {
        // Update the user interface for the detail item.
        if let detail = self.detailItem as? Pizza {     //if we have an object in the detail item
            pizza = detail
            if let label = self.pizzaTypeLabel {
                label.text = detail.pizzaType
            }
            let pizzaSizeString = NSString(format:"%6.1fin Pizza",detail.pizzaDiameter)
            let priceString = NSString(format:"%6.2f sq in at $%6.2f is $%6.2f",detail.pizzaArea(),detail.unitPrice(),detail.pizzaPrice())
            if let label = self.pizzaSizeLabel{
                label.text = pizzaSizeString
            }
            if let label = self.pizzaPriceLabel{
                label.text = priceString
            }

        }

    }

In this example, you have to bind IBOutlets of UILabels and their controller to get anything in or out of them. They are too weak to exist without the optional binding.

In later versions of Swift Apple introduced guard, whihc works similar to if but has a bit more flexibilty in unwrapping options. The button code above, for example would look like this

guard let aButton = myButton else { return }
     aButton.tintColor = UIColor.redColor()
     let type = aButton.buttonType
     let title = aButton.currentTitle
  ...

The guard unwraps and assigns like any other constant, but has a handler for nil as the else clause block. Here I return if myButton is nil and do nothing. This works the same as if but prevents the nasty nesting we have in the configureView function above.

Optionals are powerful, and in time most Swift Developers will think that Objective-C pointers are limited cousins to the flexibility of optionals. As developers get used to Swift, these will become second nature. Until then, hopefully these ten points will help guide the confused in how to use optionals with the least amount of frustration.

12 responses to “The Swift Swift Tutorial: Ten Points for Using Optionals.”

  1. The “2. Unwrap before use … use the force unwrap operator !” Example doesn’t have the ‘!’ operator shown

    1. In the first assignment, yes it is missing intentionally to give the compiler error. In the second assignment it is there. I’ll admit the probelm about force-unwrapping to simple data types is they are not as easy to see stuck on the the end of an Int identifier. It is much easier when force unwrapping to get a class’s property where the ! is in the middle. I’ll take that into consideration when I move this to any published materials.

      1. What I meant was that the width of the blog column is cutting off the end of those lines.
        Even “6. Optionals are not optional for API’s …
        func prepareForSegue(_ segue: UIStoryboard” is being cut off.
        A reader has to scroll those lines horizontally to see the code correctly.

      2. Okay I understand now. Thanks! Yeah, I really need to get that column wider, though Xcode beta 4 threw a curve at me I need to deal with first, as I just posted.

        Thanks again.

  2. […] after I finished the optionals post, It turns out there a change in Beta 4. Before Beta 4, and as described in Apple’s iBook […]

  3. […] you are not familiar with optionals, refer to the Ten Points for Using Optionals post to get yourself up to speed. Of course, keys are not always literal. We can use a variable or […]

  4. Thanks for the explanation of optionals. My inclination is to default to using optional binding, but are there certain types of variables or properties where you typically use a simpler if statement, like the example at the end of #8?

    if myButton{
    myButton!.tintColor = UIColor.redColor()
    }

    1. Sorry for the late reply. trying to catch up with a lot.

      First of all the above code is out of date. It should be

      if myButton != nil{
      myButton!.tintColor = UIColor.redColor()
      }

      Thanks for pointing it out. Thought I caught all those. Changed it in the post.
      In my experience, it’s mostly a style thing. I like for documentation purposes to be more explicit at times about what’s going on, instead of the implicit code in optional binding. The place this code would be helpful is when you want to do something in the code is nil, say lazy instantiation. I’d particularly use this here:

      if myButton != nil {
          myButton!.tintColor = UIColor.redColor()
      } else { //no button yet
          var myButton = UIButton.buttonWithType(UIButtonType.System) as? UIButton //make the button
      }
      

      This tends to read well to someone else compared to other methods. But then, I tend to be old fashioned when it comes to writing code. In my experience the basic version shows up when trying to explain optionals as in this post and in models more than views or controllers where there is a bigger chance you will hit a nil value and have to do something about it at runtime. The other difference is that optional binding is always a strong reference for the lifetime of the code block, which is why it’s necessary if you use the Split View Controller’s built in template which has some doubly weak references that ARC cleans up too fast to use. The basic if will leave things weak.

      1. That makes sense. Thanks.

  5. […] When we put the assignment of unitPriceas our condition of the if statement we use Optional Chaining. Optional chaining does three things: It unwarps our optional vaule, assigns it to a constant, and returns a value of false if the optional is nil. So with the one let statement embedded in the if statement, we remove a lot fo lines, and don’t have to unwrap unitPrice. You will see this often in code written by others. I discuss optional chaining a lot more in my more detailed post on optionals. […]

  6. […] I discuss optional chaining a lot more in my more detailed post on optionals. […]

  7. […] you are not familiar with optionals, refer to the Ten Points for Using Optionals post to get yourself up to speed. Of course, keys are not always literal. We can use a variable or […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: