Short answer: I use optional chaining when I don’t really care if the operation fails; otherwise, I use if let
or guard
.
OK, so what does that look like in practice? Let’s look at an implementation of our favorite UITableViewDataSource
method, tableView(_cellForRowAt:)
:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = viewModel.title(forRowAt: indexPath) return cell }
(This example comes straight from the Expanded Edition of Parsing JSON in Swift, so grab that if you want to see the full project.)
Here we’re using optional chaining on the cell’s textLabel
to set the text if and only if the textLabel
is non-nil. Why use optional chaining here? Because I don’t really care if the operation fails: I don’t care what happens if textLabel
is nil because (a) I’ve never seen a nil textLabel
on a UITableViewCell
and (b) I’m not sure what I could do if I did see a nil textLabel
. If this operation fails for some reason — and it’ll fail silently, since we’re using optional chaining — then we’ll see it when we run the app. We’ll have a cell (or a bunch of cells) without text on them, so we’ll know to debug this method to see what’s going on.
So what if we do care when a value is nil?
That’s usually a good time to use a guard
statement that either prints the error or reports it even more loudly (by throwing an error, perhaps.)
When might we care about a value being nil? What about when we’re parsing JSON?
func repository(with dict: JSONDictionary) -> Repository? { guard let id = dict["id"] as? Int else { print("Error: Couldn't parse id property") return nil } guard let name = dict["name"] as? String else { print("Error: Couldn't parse name property for id: \(id)") return nil } return Repository(id: id, name: name) }
It’s important for us to know if the “name” key is missing from our JSON — or if it’s the wrong type — so that we can figure out why and fix our JSON parser (or talk to the server team and ask them to fix the API).
Of course, you could turn these guard
s into if let
s if that’s your preference, and the same principles apply: if you care about what’s nil, use if let
or guard
. Otherwise, optional chaining is easy and convenient.