What Is The Difference Between Try, Try?, And Try!

Swift is a powerful, expressive language with a flexible, elegant syntax. One of the features I appreciate most is native support for error handling.

It is easy to ignore errors in Objective-C. In fact, you need to do a bit of extra work to enable error handling.

NSError *error = nil;

// Initialize Data With Contents of URL
NSData *data = [[NSData alloc] initWithContentsOfURL:URL options:0 error:&error];

if (error) {
    // Error Handling
    ...

} else {
    ...
}

This means that it is easy to ignore errors in Objective-C.

// Initialize Data With Contents of URL
NSData *data = [[NSData alloc] initWithContentsOfURL:URL options:0 error:nil];

if (data) {
    ...
}

Swift is much stricter with respect to error handling and that is a good thing. The syntax, for example, is much more expressive. The try keyword is used to indicate that a method can throw an error. To catch and handle an error, the throwing method call needs to be wrapped in a do-catch statement.

do {
    // Initialize Data With Contents of URL
    let data = try NSData(contentsOfURL: URL, options: [])

    ...

} catch {
    // Error Handling
    ...
}

Any errors that are thrown in the do clause are caught and handled in the catch clause. That is the gist of error handling in Swift.

try, try?, and try!

Many developers are confused by the different flavors of the try keyword. Swift defines three variations of the try keyword.

  • try
  • try?
  • try!

You already know how to use the try keyword. But how does it differ from try? and try!?

try?

The question mark of the try? keyword gives us a subtle hint. If we use the try? keyword and an error is thrown, the error is handled by turning it into an optional value. This means that there is no need to wrap the throwing method call in a do-catch statement.

If the operation fails, the method returns an optional without a value. If the operation succeeds, the optional contains a value.

The try? construct works very well in combination with optional binding as shown in the example below. Note that we invoke the init(contentsOfURL:options:) initializer without wrapping it in a do-catch statement. An optional is returned and, if successful, its value bound to the data constant.

if let data = try? NSData(contentsOfURL: URL, options: []) {
    print("Data Loaded")
} else {
    print("Unable to Load Data")
}

The try? keyword also works great with guard statements.

func loadContentsOfFileAtURL(URL: NSURL) -> String? {
    guard let data = try? NSData(contentsOfURL: URL, options: []) else {
        return nil
    }

    return String(data: data, encoding: NSUTF8StringEncoding)
}

try!

More dangerous is the use of try!. In Swift, an exclamation mark always serves as a warning sign. By appending an exclamation mark to the try keyword, error propagation is disabled.

This means that, if an error does get thrown, your application crashes as the result of a runtime error. As a general rule, use try or try?, and avoid or minimize the use of try!.

But when can you or should you use try!? It is perfectly fine to ignore try! altogether. If you are absolutely certain that a throwing operation will not throw an error at runtime, then it is safe to use try!.

The use of try! is similar to the use of implicitly unwrapped optionals. If you are absolutely certain that an optional contains a value, you can safely use an exclamation mark to force unwrap the value of the optional. But consider the exclamation mark as a warning that you are performing an operation that may cause your application to crash.

Question Marks and Exclamation Marks

In Swift, the uses of the question mark and the exclamation mark are intuitive and carefully chosen. A question mark indicates that you are uncertain about something. An optional, for example, may contain a value.

The exclamation mark is a warning sign. You are performing a potentially dangerous operation. You are forcing something by taking a shortcut.

Even though it usually requires a few more lines of code, it is recommended to use try and try? instead of try!. And the same applies to unwrapping optionals. That said, there certainly are use cases that justify the use of try! and forced unwrapped optionals.

Questions? Leave them in the comments below or reach out to me on Twitter.