As promised last time, here is part two of my post about Swift optionals. Here we will discuss a few more advanced aspects on how to deal with optionals, optional chaining and implicitly unwrapped optionals. These are a few more tricks to get values out of optionals, while keeping Swift code much cleaner than its predecessors. Optional chaining makes it easy to drill into multiple levels of optional values. Implicitly unwrapped optionals, while not as safe as normal optionals, are often used under the assumption that the value that it is describing is never, or usually not, nil.
Optional Chaining
What if we had to use a class optionally, and that class in turn has something optional inside it? You could use a series of “if let” checks to go into it to grab it, but Apple decided to make this easier and with less code by using optional chaining. You still have to use “if let” when performing optional chaining, but it lets you multiple levels deep with only 1 “if let“. Let’s look at this class involving a person, their pet, and the pet’s favorite toy.
class Person { var pet: Pet? } class Pet { var name: String var favoriteToy: Toy? init(name: String) { self.name = name } } class Toy { var name: String init(name: String) { self.name = name } }
So here we have a person that may or may not have a pet. Then we have a pet that has a name, but may not have a favorite toy. Then we have a toy that has a name. Let’s say we wanted to say something about that favorite toy:
if let someToy = jim.pet?.favoriteToy?.name { print("This person's pet likes the \(someToy).") } else { print("This person's pet does not have a favorite toy") }
By adding those question marks, we basically ask it whether there is a valid value or not. If pet was nil, or favoriteToy was nil, the optional binding would fail, and we would drop to the else clause.
Basically, optional chaining just returns an optional of whatever you query for at the end. Even though “name” in favoriteToy is not optional in the “Toy” class, as a result of it being called from optional chaining, you either get a nil if there is no name since it cannot be reached (either from pet or favoriteToy being nil), or you the value. But since it has to be able to return nil if it cannot reach the value, the response must be an optional.
Implicitly Unwrapped Optionals
I personally feel a bit uneasy about these. Implicitly unwrapped optionals are pretty much what they sound like. They are an optional variable that is automatically unwrapped. This is another way that you don’t have to have exclamation marks everywhere, because the forced unwrapping is built in. It is so similar to forced unwrapping, its notation is identical, just used at the variable’s declaration time:
var shouldBeASensorReadingHere: Int! = 42 var testAnswer = 30 + shouldBeASensorReadingHere
This is as opposed to a normal optional:
var unsureSensorReading: Int? = 42 var testAnswerTwo = 30 + unsureSensorReading!
Again, it is a simple example, and either one is about the same amount of code, all that is changed is where you put the exclamation mark. In a more complex algorithm though, there could be many places to unwrap it and if you, for some reason, don’t want to use optional binding, this could save a lot of exclamation marks.
Why use implicitly unwrapped Swift Optionals
There aren’t too many reasons nowadays outside of places Xcode sets for you, like for IBOutlets. The main places they would be used are for places that need to be optional because it can’t be known at initialization time, but will be a valid variable by the time it is used. IBOutlets are a great example of this. They aren’t connected to anything when a ViewController is initialized, if you call RIGHT after initialization, they will be nil, and probably crash your program. However, people don’t usually USE them at that point. The outlets are used after the ViewController is loaded and connected to its view, so by the time ViewDidLoad is called, the IBOutlets have been connected and are no longer nil, so it would be unnecessarily onerous to need them to use Optional syntax for something that is effectively never nil in normal operation.
The other place is when using Objective-C APIs that have not been updated to the Swifter way to handle variables. With Apple having updated their APIs a while back, and Objective-C nullability annotations able to be used, this should hopefully be a thing of the past, but if you use some legacy code or an Objective-C third party library, stuff might still bridge over as implicitly unwrapped optionals. Using it elsewhere, I say is at your own risk.
One other thing to note, an implicitly unwrapped optional is still a normal Swift optional, so you can still use optional binding, testing against nil, or optional chaining if you want to be safe anyway, it just is not enforced like it is with normal optionals.
Conclusion
I know this post was a bit of a long one, but I think those two aspects of Swift optionals deserve a little extra time to talk about. I in particular was confused about the use of implicitly unwrapped optionals for Objective-C classes earlier in Swift’s development, and while I’m still not the biggest fan, I see better why they are used. Any NSObject COULD be nil, and thus must be an optional, but in much of Apple’s APIs, they are used as if they are not (like the UITableView and NSIndexPath parameters), since that would make little sense in a call to cellForRowAtIndexPath.
I knew that if it was confusing me, that I had to share it here, since there is probably somebody out there that felt similar to me on that subject. Though this is changing as Apple goes through and updates the APIs to use non-Optional variables instead of implicitly unwrapped optionals, it is good to know for the times when they still choose to do so.
With the addition of nullability annotations in Objective-C, I have seen implicitly unwrapped optionals used less and less, which is a great benefit for Swift code safety.
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!