Difference Between Try, Try? and Try!

When I started learning Swift I couldn’t understand why there are different ways to handle exceptions/errors. The previous experience in JavaScript or Java didn’t help at all.

Let’s say you want to get content of some website, you get it using URL and Data structs, something like below:

let url = URL(string: “https://google.com”)!
let data = Data(contentsOf: url)

try

You can use try itself with a do-catch block when you’re not sure of the result of the operation and you want to know what happened if the function throws something. If the function throws then in catch block you can use error, it’s already passed there and you don’t need to declare it.

Example:

Function doesn’t throw:

do {
    
let url = URL(string: “https://smashswift.com”)!
    
let data = try Data(contentsOf: url)
    
print(“data: \(data))
} catch {
    
print(“error: \(error))
}

Output:

data: 24804 bytes

Function does throw:

do {
    
let url = URL(string: “smashswift.com”)!
    
let data = try Data(contentsOf: url)
    
print(“data: \(data))
} catch {
    
print(“error: \(error))
}

Output:

error: Error Domain=NSCocoaErrorDomain Code=256 “The file “smashswift.com” couldn’t be opened.” UserInfo={NSURL=smashswift.com}

try!

In this type, you don’t need to use a do-catch block because in some cases you’re sure that this function won’t throw. But what if the function will throw? Then the app will crash because you didn’t handle this. You can use this if you’re sure about the result.

Example:

Function doesn’t throw:

let url = URL(string: “https://smashswift.com”)!
let data = try! Data(contentsOf: url)
print(“data: \(data))

Output:

data: 24804 bytes

Function does throw:

let url = URL(string: “smashswift.com”)!
let data = try! Data(contentsOf: url)
print(“data: \(data))

Output:

Thread 1: Fatal error: ‘try!’ expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=256 “The file “smashswift.com” couldn’t be opened.” UserInfo={NSURL=smashswift.com}

try?

In this, you also don’t need to use a do-catch block but the difference is in the result type. try? wraps the result type with Optional and if function with try? won’t throw then you’ll get Optional(your-type) but if the function throws then you’ll receive nil.

Example:

Function doesn’t throw:

let url = URL(string: “https://smashswift.com”)!
let data = try? Data(contentsOf: url)
print(“data: \(data))

Output:

data: Optional(24804 bytes)

Function does throw:

let url = URL(string: “smashswift.com”)!
let data = try? Data(contentsOf: url)
print(“data: \(data))

Output:

data: nil