Error Handling in iOS Swift

How does ERROR handles? || do-catch-try || Swift

Yasir
The Startup
5 min readJul 9, 2020

--

We use error handling with do-try-catch in swift to respond to recoverable errors . It gives us great control over different fault scenarios that might occur in your code , such as user inputting a wrong username and password .

Further we will see in this article :

  • Why “throw” and “catch” errors
  • Why use syntax do-try-catch
  • How you can create your own custom errors types
  • Different useful scenarios for using try? and try!

WHY “throw” and “catch” Errors?

In iOS development , not all errors are bad . Some errors are part of an app’s lifecycle , such as a “Insufficient funds” message when you try to pay with your credit card. These kinds of errors are recoverable. They can be caught, handled ,and responded to appropriately.

Examples :

  • An ATM displays “Incorrect PIN code” when you try to withdraw money
  • Your car shows a “Fuel low” indicator light as you try to start the engine
  • An authentication attempt for an API returns “Wrong username/password”

You can recover from these errors by displaying an alert message, or doing something else. Your credit card gets blocked after 3 failed attempts , for example . Your car can point you to the nearest fuel pump station when you are out of gas . And you can try a difference username and password .

Swift has a class for supporting error handling with the do-try-catch block of code . do-try-catch has the same king of control over your app as if and return .

For example :

With do-try-catch you can handle errors that have been thrown with throw . We’ll get into this syntax later on. What’s interesting for now, is the throwing and catching principle.

Throwing Error in Swift

Suppose this scenario that should result in an error occurse in your code , you can throw an error like this :

In the above code , the throw keyword is used to throw an error of type RocketError.insufficientFuel when the fuel variable is less than 1000 .

Imagine we are trying to fire a a rocket :

In the above function igniteRockets(fuel:astronauts:) will only ignite the rockets if fuel is greater or equal to the 1000 and if there are at least 3 astronauts on board . The igniteRoackets(…) function is also marked with the throws keyword. This keyword indicates to whoever calls this function that errors need to be handled. Swift forces us to handle errors (or rethrow them), which means you can’t accidentally forget it!

In above code we are using an error type called RoacketError : AS

The enumeration extends Error and defines three types of error: .insufficientFuel , insufficientAstronauts(needed) and .unknownError.

Defining your own error types if very useful , because you can be very clear about what these errors mean in your code .

The throw keyword has the same effects as the return keyword . So when throw is executed , execution of the function stops at that point and the thrown error is passed to the caller of the function .

Handling Errors With Do-Try-Catch

Now we can use error handling to appropriately respond to these error scenarios . Error handling is swift is done with a so called do-try-catch block .

See:

You can also respond to error cases individually :

Converting Errors To Optionals With “try?”

The purpose of error handling is to explicitly determine what happens when an error occurs. This allows you to recover from errors, instead of just letting the app crash.

In some cases, you don’t care much about the error itself. You just want to receive value from a function, for example. And if an error occurs, you’re OK with getting nil returned.

You can do this with the try? keyword. It combines try with a question mark ?, in a similar fashion as working with optional . When you use try?, you don’t have to use the complete do-try-catch block.

Here’s an example:

Imagine the calculateValue(for:) function can throw errors, for example if its parameter is invalid. Instead of handling this error with do-try-catch, we’re converting the returned value to an optional.

One of two things will now happen:

  1. The function does not throw an error, returns a value, which is assigned to result
  2. the function throws an error, and does not return a value, which means that nil is assigned to result

Handling errors this way means you can benefit from syntax specific to optionals, such as ?? and optional binding. Like this:

And using nil-coalescing operator ?? to provide a default value:

It’s compelling to use try? to ignore or silence errors, so don’t get into the habit of using try? to avoid having to deal with potential errors. Error handling with do-try-catch is a feature for a reason, because it generally makes your code safer. Avoiding to recover from errors only leads to bugs later on.

Disabling Error Handling With “try!”

You can also disable error handling entirely, with try!.

Just as the try? keyword, the try! syntax combines try with an exclamation mark !, in a similar fashion to force unwrapping optionals When you use try!, you don’t have to use the complete do-try-catch block.

Unlike try?, which returns an optional value, the try! syntax will crash your code if an error occurs. There are two distinct scenarios in which this is useful:

  • Use try! when your code could impossibly lead to an error, i.e. when it’s 100% certain that an error will not occur
  • Use try! when you can’t recover from an error, and it’s impossible to continue execution beyond that point

Imagine you’re coding an app that has a database file embedded in it. The function to load the database throws an error when the database is corrupted. You can safely use try! to load that database into memory, because when the database is corrupted, the app won’t be usable anyway.

--

--

Yasir
The Startup

Exploring Swift, SwiftUI, and Apple Universe.