Force Unwrapping Swift Optionals: Code Smell!

Do you find your Swift code riddled with !‘s?

I’m becoming more and more uncomfortable with seeing ! throughout my Swift code. It’s just a matter of time before it’s going to bite me.

Often, I do it because it’s the “easy thing” to do at the time. But it’s dangerous.

Swift optionals are trying to help us. They force us to deal with the possibility of something not having a value.

By force unwrapping an optional with the ! operator, we’re declaring, “This will never be without a value”. Really? Never? Are you sure? Only a Sith deals in those kinds of absolutes.

When a function returns an optional, or a property is declared as optional, we are, at the very least, meant to assume that there is a possibility of nil lying underneath.

Therefore, I’m considering it a sort of “code smell” when I see it in my own code. It’s not too much to throw an if let or a guard let in there to handle the possibility of nil.

Two exceptions

Two exceptions to the code smell rule:

1 – IBOutlet and IBAction

IBOutlets and IBActions are force-unwrapped, but that’s because they get injected when the Storyboard is loaded at run-time. It’s assumed that these are connected and will be supplied when the scene is loaded. If they get unwired somehow, we want an instant crash so we know to go back to the Storyboard and re-wire things to the view controller.

2 – Required properties to be set in prepareForSegue

Along those same lines, I consider properties that must be set when navigating to a new view controller to be in the same category as an IBOutlet or an IBAction. I want to know right away if I forget to set those in prepareForSegue in the parent view controller. So I’ll often force unwrap the optional in the declaration so that there’s an as-immediate-as-possible crash if it’s not set.

Hopefully when you’re working with optionals from here on, you’ll take a second sniff when you see the ! operator.

  • Adriano Ferreira

    Hmmm, I’m also not really 100% comfortable when I see a “!” on my code. However, I can think of situations it still makes sense, for instance:

    Hmmm, I’m also not really 100% comfortable when I see a “!” on my code. However, I still see situations it make sense, for instance:

    func quickSort(array: [Int]) -> [Int] {
    guard array.count > 1 else { return array }

    // The guard above makes sure `array.first!’ won’t crash the app
    let (pivot, rest) = (array.first!, array.dropFirst())
    let lt = rest.filter({ $0 = pivot })
    return quickSort(lt) + [pivot] + quickSort(gte)
    }

    Or

    extension CollectionType where Index.Distance == Int {
    func sample() -> Generator.Element? {
    // …
    }
    }

    extension Bool {
    static func random() -> Bool {
    // Even though the `sample’ method returns an optional,
    // using `[true, false].sample()!’ won’t crash the app
    return [true, false].sample()!
    }
    }

    I’m curious to know if you’d still refactor those to use guard-let or if-let?

  • Adriano Ferreira

    Hmmm, I’m also not really 100% comfortable when I see a “!” on my code. However, I still see situations it make sense, for instance:

    func quickSort(array: [Int]) -> [Int] {

    guard array.count > 1 else { return array }

    // The guard above makes sure `array.first!’ won’t crash the app

    let (pivot, rest) = (array.first!, array.dropFirst())

    let lt = rest.filter({ $0 = pivot })

    return quickSort(lt) + [pivot] + quickSort(gte)

    }

    Or

    extension CollectionType where Index.Distance == Int {

    func sample() -> Generator.Element? {

    // …

    }

    }

    extension Bool {

    static func random() -> Bool {

    // Even though the `sample’ method returns an optional,

    // using `[true, false].sample()!’ won’t crash the app

    return [true, false].sample()!

    }

    }

    I’m curious to know if you’d still refactor those to use guard-let or if-let?

    • Andrew Bancroft

      Great scenarios, Adriano!

      In the quickSort example, the first thing I think of when I read through the code is, “Okay, he’s guarding against the array’s length being [Int] {

      guard let pivot = array.first else {
      return array
      }

      let rest = array.dropFirst()

      let lt = rest.filter({ $0 = pivot })

      return quickSort(lt) + [pivot] + quickSort(gte)
      }

      To me, it’s making explicit that I’m guarding against an non-present first element in the array. If it’s missing, I return the array. Otherwise, it’s bound to `pivot`, and the program can continue.

      But I think by adding the guard array.count > 1, you’ve essentially done your due diligence by intentionally thinking about the possible nil case.

      That’s the main thing I wanted to get at in my post. It’s a “smell”. It doesn’t always mean it’s rotten, but it should cause us to step back and go “Woah. Okay. Have I sufficiently thought about that potential for nil and dealt with it appropriately?” In your example, you did. My only argument for a refactor in quickSort is for clarity.

      I’m not sure about the sample() function – is it possible that you’d change the signature to return a non-optional Generator.Element value? My apologies – I’m just not sure what the intent is.

      Thanks again for your feedback, Adriano!

  • Jack

    For a new person to swift, what does /not/ using ! look like?
    Can you show a simple before/after example?

    Right now all I know is that swift hates everything I type, and occasionally adding ! makes it happy.

    • Andrew Bancroft

      Hi Jack!

      In most cases you’re going to want to look at “if let” or “guard let” syntax to safely deal with the Optional.

      Supposing that you have a variable “x” that holds an optional String value:

      var x: String?

      In order to _safely_ work with x without force-unwrapping it, you’d do something like

      if let unwrappedX = x {
      print(unwrappedX)
      }

      instead of doing

      print(unwrappedX!)

      Or if you know that “x” _must_ have a value, or else you want to prevent further execution by throwing an error or something, you could do something like

      guard let unwrappedX = x else {
      // throw an error or return immediately to avoid further execution
      }

      print(unwrappedX)

      There’s also “optional chaining” (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html) that you can look at.

      Hopefully some of this is helpful, Jack!

      • Jack

        Thanks Andrew that helps!
        Is there any video training that you’ve seen that you like on OSX development with Swift? I have a pluralsight sub, but they don’t have an OSX swift offering. I’m wondering if there are any ‘little guys’ out there that I might not have even heard of.

        • Andrew Bancroft

          Man, poor OS X (or macOS now, true?) – you’re right, there’s not a lot of material on developing for the desktop out there. Everyone tends to focus on the mobile platforms. If you haven’t yet, make sure you check out the macOS stuff from WWDC (from this year and years past). I’m not familiar with any other online learning platforms that might have macOS-specific training – I’m sorry.

  • Mark

    Short, sweet, and simple. I wondered about the exceptions – this is super helpful!