Skip to content

Force unwrapping is not just “not Swift-like.” It’s wrong.

Swift comes with a number of features that help developers write correct bug-free programs: optionals, safe casting, and built-in error handling. But for every one of these, there is an escape hatch: !, the force unwrapping operator.

You may know another developer or team member who plays a little fast and loose with force unwrapping. Or you don’t feel like doing the additional boilerplate to unwrap an optional, so you do it when “nobody’s looking.”

You may not have a good argument for why safe unwrapping is good and force unwrapping is bad, other than that the Swift documentation says so, or “that’s how it’s done.”

The reason behind safe unwrapping comes from a long history of languages that didn’t provide strong safeties such as these. This often resulted in trying to interpret random memory locations as objects, resulting in crashes at best, hard to debug app behavior at worst. Not using all of Swift’s safety mechanisms at your disposal is not just not Swift-like, it is bad programming.

Swift does a lot to make safe unwrapping easy to use, but sometimes the draw to use ! is very attractive. Just drop it in your code and you can ignore a bunch of nil checking or error catching or type casting you would normally need to. That is the wrong way to think about it; you shouldn’t think of ! as a way out.

Using ! is saying that you know better than your compiler; that you can reason through all the paths and uses of your code, not just now, but every possible use in the future, and decide that your force unwrapping is safe. NEWS FLASH: Compilers reason about code; interpreting code to produce executable output is their sole reason for existing. They will do a better job than you will at keeping you safe.

The ! operator is a good choice of character — okay, maybe 🚨 would have been better, or 🔥 — because you should be alarmed anywhere you see it in your code. Everywhere you see the ! operator, either defining an implicitly unwrapped property, after an Optional, as!, or try!, you shouldn’t think “this is going to be fine, so I’m force unwrapping.” You should think, “This is a place where I have specified that my code can crash.” When you frame it in those terms, you will feel much more motivated to code in ways that avoid that situation in the first place.

You might be saying right now, “But I need to interface with Objective-C NSDictionarys or NSArrays, and I know they contain all Strings, or all Integers, so I want to just force unwrap it and move on.” You can — and should — still use safe unwrapping and casting on NSDictionarys and NSArrays.

Consider this:

var foo: NSArray = NSArray(arrayLiteral: 5, 6, 7)

if let bar = foo as? [Int] {
  print(bar.reduce(0, +))
}

if let bar2 = foo as? [String] {
  print(bar2)
}
// Will not print

The safe cast checks all of the elements immediately, so the first if let prints the sum of the elements of the NSArray, while the second if let falls through because the elements are not Ints. Do this as soon as you can after receiving an NSArray, NSDictionary, or other loose Objective-C type, then your Swift code will work with the stricter Swift types exclusively.

If you have a force unwrapping, casting, or try! in your code, there is almost always some way you can restructure your code to make it safe. Get rid of your !s; your future self will thank you for it.

Comments are closed.