Leave Swift Error Propagation Enabled

A harmless Database update

I was debugging a Swift Mac app that I’m developing that uses Realm for a database.  The version of RealmSwift I was currently using was 2.10.0 as specified in my Podfile.

I opened Realm Browser to inspect a record in my database.   Having been recently updated to version 3.0.1, it alerted me that my database was using an older file format and offered to upgrade it.   I accepted without thinking much of it.

An unexpected error

When I went to launch the Mac app again, it crashed.

The problem was immediately apparent –  getting an instance of Realm() was throwing an error.

let realm = try! Realm()

This pattern of using Realm was one that I had initially gotten from an example and propagated into my own code.

The risk is clear though as is mentioned in Disabling Error Propagation:

“Sometimes you know a throwing function or method won’t, in fact, throw an error at runtime. On those occasions, you can write try! before the expression to disable error propagation and wrap the call in a runtime assertion that no error will be thrown. If an error actually is thrown, you’ll get a runtime error.”

The apparent solution was simple – just update my Pod to the latest version of Realm.

Not quite

Updating the Pod, though desirable, was not the full solution.   This is an app that is intended to assist iOS developers in app creation (a later blog post will describe this once it is finished).  As an app developer myself, I could fully expect that some of my future users might be curious and launch Realm Browser themselves.  This of course could result in crashes for those users.

The right solution was to handle any errors from Realm.

   var realm: Realm
   do {
     realm = try Realm()
   }
   catch {
     // Handle error
   }
        

I might for example let the user know that they need to update the Mac app to the latest version to be compatible with the database.

Eliminate try! everywhere

I did a search through my project and found a few other instances where I could be asking for trouble – all of them using NSRegularExpression.

Here is another (contrived) example that could crash:

   let namePattern = "\\'("
   let nameRegEx = try! NSRegularExpression(pattern: namePattern, options: [])
   let nameMatches = nameRegEx.matches(in: name, options: [], range: NSRange(location: 0, length: name.count))
        

I think my policy going forward will be to avoid using try! at all and instead handle all errors thrown by try.  Using try! isn’t necessary and is just asking for trouble 🙂

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s