Swiftly Discovering an Error

Datetime:2016-08-22 22:35:48          Topic: Coder  Objective-C           Share

At work last week, I was debugging some odd behavior in one of our apps. A user, on a detail screen, would tap a Save button, and nothing would happen. Not a crash, not an error message, no log entries. Just, nothing.

I started digging into the code, and quickly found we were trying to add this new item represented by the detail screen onto a custom collection. Something along these lines ( the names have been changed to protect the guilty ):

[self.customCollection addItem:self.collectionItem];

As it turns out, a couple of classes above this one, the insance of customCollection wasn’t being properly initialized; it was simply nil .

That means in the code above, we were passing a message to nil . In Objective-C, that means the message is dropped on the floor, and ignored.

In many other languages, such as C♯, calling a method on a null variable would cause a crash. Messaging to nil being acceptable is considered a feature in Objective-C, and not a bug. Crashes are never a good thing, after all.

In Swift, by comparison, we can only have nil values on Optional s. We do have the handy optional chaining syntax, however, that would change the code above to:

self.customCollection?.add(item: self.collectionItem)

As a Swift developer, seeing that ? would immediately cue to me that it’s possible for customCollection to be nil . Something that is worth investigating.

That being said, any Objective-C developer worth their salt will think the same of any class instance. To a Swift developer, that sounds exhausting, but it’s still a reasonable point. Further, many Swift developers only use optional chaining in cases they’re pretty damn sure things will either be non- nil , or it’ll work itself out if things are nil . The ? may get overlooked.

In our case, where nil really is bad news, a good Swift developer would improve upon the above:

guard let collection = self.customCollection else {
    // Take evasive action, or just punt:
    fatalError("Custom Collection instance cannot be null!")
}

// If we get here, we are *guaranteed* that collection is non-nil.
collection.add(self.collectionItem)

Here, it’s made explicitly obvious what’s happening: the guard let indicates this thing had better be true, or else bad things have happened .

“But wait!” shouts the Objective-C developer! “We have NSAssert !”

Okay, sure. But NSAssert isn’t always enabled; in fact, in general, it’s disabled by most in release builds.

The point isn’t that Swift’s Optional s or guard let have no equivalents in Objective-C. The point is that thinking deliberately about these things—and proactively protecting yourself from error conditions—is a fundamental part of how you write Swift.

Some people may find being that concerned with what is Optional and what isn’t to be exhausting. I find it to be lovely. I find myself being far more deliberate with the Swift code that I write. In many ways, it’s reminiscent of the C♯ I wrote in the past, but with better tools such as guard let and optional chaining (which was just added in C♯ 6.0 , actually).

I like Swift, and I like being that careful with my code. Swift instills a care in me that I like to think is innate, but is now compulsory.





About List