Swift do-try-catch syntax and implementation


In Swift, the do-try-catch statement is used to handle errors that can be thrown by a function or method. It provides a structured way to catch and handle errors in your code. In your codebase, you cannot handle all runtime errors when they come but using try-catch you can handle them without crashing your application.

The do-try-catch Syntax

The do block is used to wrap code that could throw an error. Inside the do block, you call the function or method that throws an error.

The try keyword is used before calling any function or method that may throw an error. This tells the Swift compiler that the following code can potentially throw an error and should be handled accordingly.

If an error is thrown inside the do block, the code immediately jumps to the catch block. The catch block provides an opportunity to handle errors structured. You can catch an error by specifying its type using the catch keyword followed by the error type. You can also catch any error using the generic catch block.

Here's an example of the basic syntax

do {
   // code that can throw an error
   try someFunctionThatMayThrowAnError()
} catch {
   // Handle the error here
}

You can also catch specific types of errors

do {
   // code that can throw an error
   try someFunctionThatMayThrowAnError()
} catch CustomError.someError {
   // handle CustomError.someError here
} catch CustomError.anotherError {
   // handle CustomError.anotherError here
} catch {
   // handle any other error
}

Some Examples of Swift do-try-catch Syntax

Example 1: Reading Data From a File

To read the contents of the file at the supplied path, we use the Data(contentsOf:) initializer in this function. If the file does not exist or if we do not have permission to access it, this initializer may raise an error.

To turn the data into a string, we use the initializer String(decoding:as:). If the input data is not a valid UTF-8 string, this initializer may potentially cause an error.

We will see how to handle an error when the file path is incorrect or the file does not exist.

Here is an example −

import Foundation
func readFile(atPath path: String) throws -> String {
   let data = try Data(contentsOf: URL(fileURLWithPath: path))
   return String(decoding: data, as: UTF8.self)
}
do {
   let data = try readFile(atPath: "/path/to/file.txt")
   print(data)
} catch {
   print("Error: \(error)")
}

Output

Error: Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"

In the above example, we defined a function called readFile(). This method accepts an argument which is the file path. This method can throw an error as indicated in the method signature. While we call this method with a file path, we call it using a do-catch block. If any error occurs during file reading, the catch block will be executed.

Example 2: Making a Network Request

In this example, we use the Data(contentsOf:) initializer to make a network request to the specified URL. This initializer can potentially throw an error if there is a problem with the network connection or if the URL is invalid.

We use the JSONSerialization.jsonObject(with:options:) method to parse the response data as a JSON object. This method can also throw an error if the data is not valid JSON or if the options are invalid.

import Foundation
func makeRequest(url: URL) throws -> [String: Any] {
   let data = try Data(contentsOf: url)
   let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
   return json
}
let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")!
do {
   let json = try makeRequest(url: url)
   print(json)
} catch {
   print("Error: \(error)")
}

Output

["userId": 1, "body": quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto, "id": 1, "title": sunt aut facere repellat provident occaecati excepturi optio reprehenderit]

In this example, we construct a function called makeRequest(url:) that sends a network request with the help of a URL. If there is a network connection issue or if the URL is wrong, the function may throw an error.

To call this method and manage any potential issues, we utilize the do-try-catch syntax. In the event that an error is thrown, the catch block is used to capture it and output an error message. We print the JSON response to the console if no problems are raised.

Example 3: Nested do-try-catch Blocks

import Foundation
enum MyError: Error {
   case somethingWentWrong
}
func doSomething() throws {
   throw MyError.somethingWentWrong
}
func doSomethingElse() throws {
   try doSomething()
}
do {
   try doSomethingElse()
} catch MyError.somethingWentWrong {
   print("Oops! Something went wrong in doSomething().")
} catch {
   print("Unknown error: \(error)")
}

Output

Oops! Something went wrong in doSomething().

We have two methods in this example: doSomething() and doSomethingElse(). MyError of type is thrown by doSomething(). When anything goes wrong, doSomethingElse() invokes doSomething() with the try keyword.

We use "try" to use the problematic function doSomethingElse() in the do block. If an error occurs, the relevant catch block will be run. In this instance, we have two catch blocks: one that is particular to the MyError.somethingWentWrong situation and the other that is general and captures all errors.

Conclusion

In conclusion, the do-try-catch line is a key element of Swift that enables developers to manage errors in their code in a systematic and dependable manner. It offers a way to handle problems functions or methods could throw. This can stop crashes and increase your code's robustness and dependability. You may build a more reliable and stable program that manages possible problems in a predictable and controllable manner by employing do-try-catch blocks.

Updated on: 04-May-2023

3K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements