Ghostboard pixel

try!

try!

Error handling is a very important topic and I’ve written already a blog post about that topic. You can also check out my talk about that topic on the Swift Summit in San Francisco. In this post we will discuss when you should use try!.

Hint: This post has been updated to Swift 3, iOS 10 and Xcode 8

Error Handling

Let’s start by quickly refreshing the topic error handling. You can define an error type by using an enum that implements the Error protocol:

enum MyErrorType : Error {
    case SomeErrorCause
    case AnotherErrorCause
}

Now, a function can throw the error:

func testFunction() throws {
      
      throw MyErrorType.SomeErrorCause
        
}

If you are calling a function that is able to throw an error, you have to catch all possible errors:

do {
      try testFunction()
} catch {
      print("there was an error...")
}

However, there is one situation when you don’t have to catch the error.

try!

By using the keyword try!, you are telling the compiler: “I’m 100 percent sure that there will be no error, so I don’t have to catch it!”. Let’s use it in our example:

try! testFunction()

However, if the function does throw an error, you will have a runtime exception. That’s the case in our example because our test function always throws an error.

So, why should you then even use try!? You can use it, when you are absolutely sure, that there will be never an error at runtime. A very good example for that is copying a file from inside the app bundle:

let sourcePath = Bundle.main.path(forResource: "text", ofType: "txt")!
let destinationPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, .userDomainMask, true).first! + "/text.txt"
        
do {
    try FileManager.default.copyItem(atPath: sourcePath, toPath: destinationPath)
} catch {
    print("error")
}

The function copyItemAtPath can throw an error, so we have to catch it. In most cases, it could happen very easily that a file cannot be copied due to a lot of different reasons. However, in this example we are accessing a file inside the app bundle. The app bundle is read-only, so the file will always be in the app bundle. And because we are absolutely sure that the file is there, there is no good way to handle the error in this case. Let’s use try! instead:

let sourcePath = Bundle.main.path(forResource: "text", ofType: "txt")!
let destinationPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, .userDomainMask, true).first! + "/text.txt"
        
try! FileManager.default.copyItem(atPath: sourcePath, toPath: destinationPath)

The only way that this could go wrong is that we’ve forgotten to put the file inside the app bundle or because of a typo. But then the app would crash at development time and we could fix it.

To summarise it, you can use try! if there’s no chance that there will be an error at production time. Additionally, by using try! you can easily check at development time whether everything is working fine because the app will crash immediately when you are testing the app. 

But generally speaking, you should only use it when you are very sure what you are doing! And in most cases you should use the normal try – catch way.

References

Title Image: @ Pavel Burchenko / shutterstock.com