Swift Error handling – Swift try, do catch, throws

Filed Under: Swift
swift error handling

Swift error handling is a very important aspect of writing better code. Swift try statement is used for error handling in swift programs. Let’s get started by launching XCode playground.

Swift Error Handling

Swift Error Handling is all about handling the failing conditions gracefully.

An error can lead to runtime errors or changes in the flow of the program.

We come across different kinds of errors in our projects:

  • Logic Errors
  • Type Conversion Errors.
  • External Errors such as FileNotFound etc.

The brute force way to handle errors is by using if else statements where we check each and every possible error. But this can lead to bloated codes with too many nested conditions.

In Swift, Errors are just values of a certain type. Swift does not support checked exceptions.

Swift Error Protocol

Error Protocol is just a type for representing error values that can be thrown.

Swift requires you to create a custom Error type. Typically an Enum is used which conforms to the Error Protocol.

The Error Protocol is more or less empty. Hence you don’t need to override anything from them. Error Protocol is a must for Error Handling and creating Error types.

Let’s create a basic enum which conforms to this Error Protocol.


enum UserDetailError: Error {
    case noValidName
    case noValidAge
}

Now let’s use this Error Type in our classes and functions.

throws and throw

If a function or an initializer can throw an error, the throws modifier must be added in the definition itself right after the paratheses and just before the return type.


func userTest() throws -> <Return Type> {

}

The throws keyword would propagate the error from the function to the calling code.
Otherwise, a non-throwing function must handle the error inside that function’s code itself.

throw keyword is used for throwing errors from the error type defined.

Let’s look at an example demonstrating throws and throw in a function:


func userTest() throws {
    if <condition_matches> {
    //Add your function code here
    }
    else{
    throw UserDetailError.noValidName
    }
}

In Error Handling, guard let is useful in the sense that we can replace the return statement in the else block with the throwing error. This prevents too many if else conditions.
Let’s look at it with the example below.


func userTest(age: Int, name: String) throws {
    
    guard age > 0 else{
    throw UserDetailError.noValidAge
    }
    
    guard name.count > 0 else{
       throw UserDetailError.noValidName
    }
}

Note: You cannot add the Error type after the throws keyword in Swift.

In the above code, if the condition in the guard let fails it’ll throw an error and the function would return there itself.
Let’s look at how to handle these errors.

Swift try, do-catch

In Swift, contrary to Java, do-catch block is used to handle errors in place of try-catch.

Every function that has throws needs to set in the try statement since it has a potential error.

Swift try statement is executed only when it is inside the do-catch block as shown below.


do{
try userTest(age: -1, name: "")
} catch let error {
    print("Error: \(error)")
}

Below image shows the output of above program.

swift error handling, swoft try catch example

Alternatively we can do this:


do{
try userTest(age: -1, name: "")
}
catch UserDetailError.noValidName
{
    print("The name isn't valid")
}
catch UserDetailError.noValidAge
{
    print("The age isn't valid")
}
catch let error {
    print("Unspecified Error: \(error)")
}

Throwing Errors in Initializers

We can add throws in the initializer in the following way.


enum StudentError: Error {
    case invalid(String)
    case tooShort
}

class Student {
    var name: String?
    init(name: String?) throws {
        guard let name = name else{
            throw StudentError.invalid("Invalid")
        }
        self.name = name }

    func myName(str: String) throws -> String {

        guard str.count > 5
            else{
                throw StudentError.tooShort
        }

        return "My name is \(str)"
    }
}

Now to initialise the class we normally do the following, right?


var s = Student(name: nil)
//compiler error

WRONG

Since the intializer is throwing errors we need to append try keyword as shown below.


do{
var s = try Student(name: nil)
}
catch let error
{
    print(error)
}

//prints
//invalid("Invalid")

Let’s call the class function on the object too as shown below.
swift try example

Swift try, try? and try!

  • Swift try is the most basic way of dealing with functions that can throw errors.
  • try? is used to handle errors by converting the error into an optional value. This way if an error occurs, the function would return a nil and we known Optionals can be nil in Swift. Hence for try? you can get rid of do-catch block.
  • try! is used to assert that the error won’t occur. Should be only used when you’re absolutely sure that the function won’t throw an error. Like try?, try! works without a do-catch block.

var t1 = try? Student(name: nil)
var t2 = try! Student(name: "Anupam")

That’s all for Swift error handling and swift try examples.

Reference: Apple Docs

Comments

  1. pratik says:

    nice tutorial

    1. luis says:

      nice explanation

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages