Coding Explorer Blog

Exploring how to code for iOS in Swift and Objective-C

  • Home
  • Apps
  • About
  • Contact

Multiple Optional Bindings in Swift

Xcode 11.6 Swift 5.2.4

Last updated on August 12, 2020

Shortly after my last post Segue from UITableViewCell Taps in Swift, Apple released Xcode 6.3 Beta 1, which includes Swift 1.2.  There are many updates to the language that I was quite happy about, but let’s talk about my favorite one today, improved Optional Binding.

The new version allows you to bind multiple optionals, as well as check a boolean expression related to them in a single line, avoiding the nesting we currently must do when working with multiple Optional Bindings.

Multiple Optional Bindings — Avoid the “Pyramid of Doom”

So, I apparently called what everybody else calls the “Pyramid of Doom” the “Tower of Ifs” in my previous article, despite hearing of the Pyramid from the Edge Cases podcast, ah well.  They were more talking about highly nested callbacks via blocks or closures, which isn’t exactly this, but the nesting required for multiple Optional Bindings in early Swift make the term appropriate in this context as well.  Nonetheless, with this improvement, let’s look at what we wrote last time for prepareForSegue:

Before Multiple Optional Bindings Version

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == blogSegueIdentifier {
                if let destination = segue.destination as? BlogViewController {
                    if let blogIndex = tableView.indexPathForSelectedRow?.row {
                        destination.blogName = swiftBlogs[blogIndex]
            }
        }
    }
}

Like I said before, I’m not a fan of that Pyramid of Doom there.  Now, you can chain multiple if-let statements, which would result in the following code:

After Multiple Optional Bindings Version (First Refactor)

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == blogSegueIdentifier {
        if let destination = segue.destination as? BlogViewController,
           let blogIndex = tableView.indexPathForSelectedRow?.row
        {
            destination.blogName = swiftBlogs[blogIndex]
        }
    }
}

Since we only had 2 if-let statements, it doesn’t look a WHOLE lot better, but it does keep us from needlessly nest the code.  This is especially important if there was an else associated with this if statement (then there would be elses nested in there, and that would look even worse).  Thanks to Colin Eberhardt for pointing even more issues (and a little history on the term) on his post Tearing Down Swift’s Optional Pyramid of Doom.  He also goes into some ways to deal with this before this change was implemented using some functional programming.  It’s definitely an interesting read.

Multiple Optional Bindings with Normal Boolean Conditional

We could have used the where clauses discussed below to remove 1 more level of nesting in the above example, but that use is inconsistent with how where is used in other contexts, usually checking the objects it is working on, or components thereof.  The segue identifier, nor the blogSegueIdentifier are components of the destination of blogIndex, so it seemed like bad practice to me.  Now, we have a better option!

Now, we can start with a normal if-statement if we want, and then continue with Optional Binding when the initial if-statement evaluates to true, so, now, the above example becomes:

After Multiple Optional Bindings Version (Second Refactor)

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if  segue.identifier == blogSegueIdentifier,
        let destination = segue.destination as? BlogViewController,
        let blogIndex = tableView.indexPathForSelectedRow?.row
    {
        destination.blogName = swiftBlogs[blogIndex]
    }
}

There we have it.  While the conditional itself is rather long, it is in ONE level of nesting.  There isn’t much we would do if it was the correct segue, but the destination and blogIndex couldn’t be optionally bound, we don’t really need to have an else for each of those individual cases.  If any of these evaluate to false, the whole conditional fails, and we don’t have to worry about dealing with multiple else clauses for the intermediate if-statements.

If you need those, you can do it the old way, but especially when you have many optionals to use, getting into 5 levels or more of nesting can get a bit… interesting to work with.  Maybe somebody might want the intermediate levels when debugging, but all that really does here is let you know if the destination isn’t a BlogViewController (which really should be caught in testing, rather than with “else” clauses in production code), or if there is no selected row in the tableView (which shouldn’t happen because that is what starts this particular segue, unless it was cleared beforehand, I suppose).

If you had more than one segue you would probably use a switch statement instead of an if-statement.  If you only have a small amount though, this could still be of use.  You can read more about Switch statements in the earlier post Loops, Switch Statements, and Ranges in Swift.

Now we can have all of our Multiple Optional Bindings and conditional checking in one line.  Is it almost as verbose as the original way?  Yes, since we still have to write the code to actually do what we need (like reading the indexPath and casting the destinationviewController).  However though, we do not have to nest multiple Optional Bindings inside themselves, and that’s the important part.

Conclusion

I am also a fan of the delayed initialization of constants (“let” values), requiring them to by initialized before they are used, but not necessarily when they’re declared.  Type casting has seen some changes as well, and NSSet finally gets a Swift equivalent called Set.  You can read about the new Set type in the newer post Swift Set Type.

As far as non-syntax changes, I am glad they have add incremental building, so that every Swift file does not need to be recompiled each time, particularly if only one has been changed.  They have also better optimized many things under the hood, especially for Debug builds.

I am glad since the original writing of this post, that they changed the indexPathForSelectedRow from a method to a property, since it really was just a getter method in the first place.  It might be just a couple less parentheses, but it still makes it look just a bit cleaner.

I hope you found this article helpful.  If you did, please don’t hesitate to share this post on Twitter or your social media of choice, every share helps.  Of course, if you have any questions, don’t hesitate to contact me on the Contact Page, or on Twitter @CodingExplorer, and I’ll see what I can do.  Thanks!

Sources

  • The Swift Programming Language – Apple Inc.

Filed Under: Swift Tagged With: optionals, Swift

Subscribe to the Coding Explorer Newsletter

* indicates required

Follow Us

Facebooktwitterrss

Recent Posts

  • Error Handling in Swift
  • Creating and Modifying a URL in your Swift App
  • Watch Connectivity in Swift — Application Context
  • watchOS Hello World App in Swift
  • API Availability Checking in Swift

Categories

  • Class Reference
  • General
  • Interface Builder
  • My Apps
  • Objective-C
  • Swift
  • Syntax
  • Tutorial
  • Uncategorized

Archives

  • May 2016
  • March 2016
  • February 2016
  • December 2015
  • July 2015
  • June 2015
  • April 2015
  • February 2015
  • January 2015
  • December 2014
  • November 2014
  • October 2014
  • September 2014
  • August 2014
  • July 2014
  • June 2014
  • May 2014
  • April 2014
  • March 2014
  • January 2014
  • November 2013
  • September 2013
  • August 2013
  • July 2013
  • Terms Of Use
  • Privacy Policy
  • Affiliate Disclaimer

Subscribe to the Coding Explorer Newsletter

* indicates required

Copyright © 2025 Wayne Media LLC · Powered by Genesis Framework · WordPress