The article will aim to answer the question: what’s the best way to unwrap optionals in Swift? To answer that question we will explore what optionals actually are, and why Swift uses them. We will then consider a couple of approaches for how you might want to be unwrapping them in your code with a consistent style.
What are Optionals?
Lets first confirm our understanding of what optional are: Optionals are actually a special type in Swift which wraps other types inside it. To illustrate this, consider the fact that the types String and String? are actually two different types in Swift.
To clarify: a String is definitely going to be an initialized string, on the other hand, a “String?” is actually an Optional<String>, a special type that will need to be “unwrapped” for us to use it. As we can see then, “Swift’s type system usually shows the wrapped type’s name with a trailing question mark (?) instead of showing the full type name”(Ref#: F).
Under the hood the Optional type is a generic enum with two cases: Optional
and Optional
where a wrapped value is stored.
Essentially then the Optional
type is like a box in which can either contain a value, or it can contain nothing (nil). Very much akin to the classic game where a person trying to find a ball under a set of shuffled cups, it’s not obvious whether there is going to be something under a cup until one actually looks under it.
You use optionals in Swift when attempting to represent an object for which a value may not yet have been assigned, or where a value is not present (i.e. for situations where a value may be absent).
Swift creates this wrapper object which might either contain a value, meaning you can “unwrap” the optional to access the value it contains, or alternatively it may not contain a value at all in which case if one attempted to “force unwrap” the optional one would experience an error (Ref#: C).
How is this Different From Objective-C?
Neither the C language or the Objective-C language uses optionals “The nearest thing in Objective-C is the ability to return nil
from a method that would otherwise return an object, with nil
meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structures, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound
) to indicate the absence of a value. This approach assumes that the method’s caller knows there’s a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants” (Ref#: C).
“Using optionals is similar to using nil
with pointers in Objective-C, but they work for any type, not just classes. Not only are optionals safer and more expressive than nil
pointers in Objective-C, they’re at the heart of many of Swift’s most powerful features” (Ref#:G).
The argument for adding optionals to the Swift language centers on the fact that they enforce good programming practices (they force the programmer to write more explicit code), and allow for better code checking at compilation time (Ref#: L).
“Optionals are Swift’s way of unifying the representation of Nothingness. By using them, we lose some of the ease and flexibility of nil messaging, but gain compile-time checking, safety and a consistent way of dealing with the same problem, regardless of variable type” (Ref#: N).
What’s the “Best” Way to Unwrap Optionals?
So from the above, we learned that since Optionals are a special type, and basically contain either a value or nothing we can’t just directly use them, we have to unwrap them (just like you can play with your new action man figure at Christmas without unwrapping it first). So let explore how this is done in code:
The If / Let Approach (Optional Binding)
One common and widely favored approach within the Swift community is to safely using options is using an if let
statement thus:
This is a type of optional binding as we create a new property an attempt to assign the contents of a given optional to that property, but if we can’t we fall back to our else statement.
Using a Guard Statement (another kind of Optional Binding)
Another way to safely unwrap is by using a guard
statement, for example, we can create a function that takes an optional and use a guard let statement to check if there anything inside the optional passed into the function:
If there’s nothing inside that optional were still cool as our guard statement will cover our backs:
Using the Nil-Coalescing Operator ( ?? )
One clever way to stop optionals causing issues is to provide a default value via the “nil-coalescing operator” or where you put a default value after “??” when setting a var or let to equal some optional which could be nil:
We thus can use this operator to supply a default value for something we need to use later in our code in case the Optional contains nil instead of being populated by a value.
(Ref#: F)
If Statements and Forced Unwrapping
One way that force unwrapping can be used safely is testing for the existence of an optional using a conditional syntax, like the example below, to verify that our optional is not equal to nil:
Because a swift optional which does not contain a value will have the special value of nil we can use a if statement to check whether our object contains a value, like the above code snippet. This approach may be one avoided by some development teams as it can be easier to spot force unwrapping when we rule out using the if statement approach.
(Refs#: A & H)
Optional Chaining
As Paul Hudson put’s it optional chaining “lets you run code only if your optional has a value” such that it allows querying and calling properties, methods, and subscripts on an optional that could currently be nil. If the optional contains a value the call succeeds, alternatively if the optional is nil, the call will return nil (Ref#: G)
Expanding on this: the main difference between force unwrapping an optional and optional chaining is that “optional chaining fails gracefully when the optional is nil
, whereas forced unwrapping triggers a runtime error when the optional is nil
” (Ref#: G).
This is easier to see working in an example: In the first example below when we set catsFaveFood
we do so using optional chaining where we effectively say, if myCat isn’t nil then set catsFaveFood equal to the value of favoriteFood inside the myCat object.
However, we are also able to safely remove the line marked with the comment “// 3” because, even if we don’t set the value of myCat, the line “let catsFaveFood = myCat?.favoriteFood” is still safe because it will “fail gracefully” such that the value of catsFaveFood will in this case not be set.
Force Unwrapping
Using force unwrapping is almost always a bad idea. If you find the below example in your code (with no check for nil prepended), then something is probably amiss:
Implicitly Unwrapped Optionals
When we declare an optional type, we typically declare it as optional thus, such that we need to unwrap it to use it:
But we might also choose to use Implicit Unwrapping:
Behind the scenes, it’s worth noting that the implicitly unwrapped optional
is actually an enum which a type of ImplicitlyUnwrappedOptional
while the optional
is an enum with the type Optional
(Ref#: M).
Given the issues using an implicitly unwrapped optional could cause, why would we want to use it?
“If you declare a property as optional, then you need to use optional binding or optional chaining every time you access the value of the optional”, this may not be an issue as such, but it can lead to really messy looking code where you constantly have to unwrap objects in multiple places (Ref#: H).
Where we might often see this is with things like outlets (like when you control drag from a nib or storyboard and create an outlet to access the UI item), so it’s often the stuff that we really need in order for the program to continue to do what it was intended to:
With these, we essentially know that they are going to be available (after a certain point in the lifecycle of a view), so to avoid having to add in extra checks we just assume they will be populated when we come to access them.
Generally speaking it’s really not a good idea to use implicit unwrapping for stuff that isn’t outlet related, there are some cases though such as when you are using the Codable protocol to decode JSON, where it may make sense to implicitly unwrap some of the vars to keep from having to always unwrap these (perhaps where one object is nested in another which has already been checked for nil).
Conclusion
So reviewing the above, is there a best way to unwrap optionals? For me, I think we can use a mixture of approaches just as long as we don’t force unwrap optionals without first checking that they are not nil. I have certainly found that there are those who dislike the “if anOptional != nil” approach as they tend to favor a style of code where we don’t see bangs (“!”) after optionals anywhere in code where we can choose a different structure such as the Optional Binding (if let) approach which avoids the need for using these bangs and makes code potentially easier to review when looking for cases of these.
References
A: https://stackoverflow.com/questions/25195565/how-do-you-unwrap-swift-optionals
B: https://hackernoon.com/swift-optionals-explained-simply-e109a4297298
C: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID309
D: https://developer.apple.com/documentation/swift/optional
E: https://www.youtube.com/watch?v=7a7As0uNWOQ
F: https://www.youtube.com/watch?v=ZL8BFK8bVjk
G: https://docs.swift.org/swift-book/LanguageGuide/OptionalChaining.html
H: https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html
F: https://developer.apple.com/documentation/swift/optional
G: https://www.youtube.com/watch?v=fVaGY9wUZnQ
H: https://stackoverflow.com/questions/24006975/why-create-implicitly-unwrapped-optionals-since-that-implies-you-know-theres
I: https://cocoacasts.com/embracing-optionals-in-swift
J: https://cocoacasts.com/swift-fundamentals-working-with-optionals
K: https://www.hackingwithswift.com/read/0/13/optional-chaining
L: https://stackoverflow.com/questions/35546224/what-makes-swifts-optional-safer-than-objective-cs-nil
M: https://krakendev.io/blog/when-to-use-implicitly-unwrapped-optionals
N: http://commandshift.co.uk/blog/2014/06/11/understanding-optionals-in-swift/
Updated: 31/05/2019
Comments