Error Handling in the Swift Language


Error management in Swift is a technique for dealing with mistakes that happen while the code is running. It enables you to create code that smoothly predicts and deals with mistakes rather than crashing during execution. You will see some examples of how to deal with Swift code errors in this post.

The try, catch, and throw keywords are just a few of the error-handling tools offered by Swift. Together, these keywords make it possible for programmers to create error-free code.

There are Some Points of How Error Handling Works in Swift

  • If a function can throw an error due to any reason, you can be marked with the throws keyword in the function declaration.

  • When calling a function that can throw an error, you must use the try keyword to indicate that you know the possibility of an error being thrown.

  • If an error is thrown, it can be caught and handled using the catch keyword.

  • An error can be thrown using the throw keyword.

Here's a syntax for how error handling can be used in Swift −

enum CustomError: Error {
   case errorOne
   case errorTwo
}

func doSomething() throws {
   // This function can potentially throw two types of errors
   if someCondition {
      throw CustomError.errorOne
   } else if someOtherCondition {
      throw CustomError.errorTwo
   } else {
      // Do something else
   }
}
do {
   try doSomething()
   // No error was thrown, do something else
} catch CustomError.errorOne {
   // Handle error one
} catch CustomError.errorTwo {
   // Handle error two
} catch {
   // Handle all other errors
}

The doSomething() method in this example has the ability to produce two of the mistakes listed in the CustomError enumeration. The try keyword is used to signal that we are aware that an error might be generated when calling the method.

A catch block can be used to capture and manage errors if they are thrown. In this example, each possible error category is represented by a distinct catch block, and a generic catch block is used to manage all other errors.

Throwing an Initializer in Swift

A remarkable thing is that you can also create a throwing initializer. Particularly useful when you want to validate properties for initializing a certain object. For example, you might want to validate a username before creating a User object.

Example

import Foundation
struct User {
    
   enum ValidationError: Error {
      case emptyName
      case shortName(nameLength: Int)
   }
   let name: String
   init(name: String) throws {        
      guard !name.isEmpty else {
         throw ValidationError.emptyName
      }       
      guard name.count > 2 else {
         throw ValidationError.shortName(nameLength: name.count)
      }
      self.name = name
   }
}
// Handling Errors in Swift with a do-catch statement
do {
   let user = try User(name: "Alex")
   print("Created user with name \(user.name)")
} catch {
   print("User creation failed with error: \(error)")
}

Output

Created user with name Alex

Swift Try Catch: Handling Errors in Swift with a do-catch Statement

To handle an error in Swift, you use the do-catch statement. Here's an example −

Example

import Foundation
struct User {   
   enum ValidationError: Error {
      case emptyName
      case shortName(nameLength: Int)
   }
   let name: String
   init(name: String) throws {       
      guard !name.isEmpty else {
         throw ValidationError.emptyName
      }       
      guard name.count > 2 else {
         throw ValidationError.shortName(nameLength: name.count)
      }
      self.name = name
   }
}
do {
   let user = try User(name: "")
   print("Created user with name \(user.name)")
} catch {
   print("User creation failed with error: \(error)")
}

Output

User creation failed with error: emptyName

Catching a Specific Type of Error

As we can’t specify the error type which will be thrown by a method we have to take into account that different kinds of error types can be thrown. Therefore, you want to catch and handle specific error types in a separate catch statement.

Example

import Foundation
struct User {    
   enum ValidationError: Error {
      case emptyName
      case shortName(nameLength: Int)
   }
   let name: String
   init(name: String) throws {        
      guard !name.isEmpty else {
         throw ValidationError.emptyName
      }        
      guard name.count > 2 else {
         throw ValidationError.shortName(nameLength: name.count)
      }
      self.name = name
   }
}
do {
   let user = try User(name: "A")
   print("Created user with name \(user.name)")
} catch User.ValidationError.emptyName {
   
   // Called only when the `User.ValidationError.emptyName` error is thrown
   print("User creation failed due to empty name")
} catch User.ValidationError.shortName(let nameLength) where nameLength == 1 {
   
   // Only when the `nameToShort` error is thrown for an input of 1 character
   print("User creation failed due to short name")
} catch let error {
   print("User creation failed with error: \(error)")
}

Output

User creation failed due to short name

Conclusion

Swift has excellent error management. It handles the non-happy flow while also enabling you to create legible code. If necessary, we can manage specific situations by being able to capture particular error kinds or by using the where keyword. Make sure your methods hurl whenever they can to be a decent citizen!

You can create code that manages failures in Swift that is controlled and graceful, ensuring that your application keeps running even when something unanticipated occurs. It enables you to give the customer more detailed error notifications, which makes it simpler for them to comprehend and fix the problem.

Updated on: 04-May-2023

108 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements