Chapters

Hide chapters

Swift Apprentice: Beyond the Basics

Second Edition · iOS 18 · Swift 6 · Xcode 16.2

Section I: Beyond the Basics

Section 1: 13 chapters
Show chapters Hide chapters

5. Error Handling
Written by Matt Galloway

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Skilled developers design their software for errors. Error handling is the art of failing gracefully. Although you completely control your code, you don’t control outside events and resources. These include user input, network connections, available system memory and files your app needs to access.

In this chapter, you’ll learn the fundamentals of error handling: what it is and different strategies for implementing good error handling.

What is Error Handling?

Imagine you’re in the desert, and you decide to surf the internet. You’re miles away from the nearest hotspot with no cellular signal. You open your internet browser. What happens? Does your browser hang there forever with a spinning wheel of death, or does it immediately alert you that you have no internet access?

When designing the user experience for your apps, you must think about the error states. Think about what can go wrong, how you want your app to respond, and how to surface that information to users to allow them to act on it appropriately.

First Level Error Handling With Optionals

Throughout this book, you have already seen an elementary form of error handling in action. Optionals model missing information and provide compiler and runtime guarantees that you won’t accidentally act on values that are not available. This predictability is the foundation of Swift’s safety.

Failable Initializers

When you try to initialize an object from external input, it may fail. For example, if you’re converting a String into an Int, there is no guarantee it’ll work.

Optional Chaining

Have you ever seen a prompt in Xcode from the compiler that something is wrong, and you are supposed to add ! to a property? The compiler tells you you’re dealing with an optional value and sometimes suggests you deal with it by force unwrapping.

map and compactMap

Let’s say you want to create an array of pets the team owns. First off, you need to create an array of team members:

Error Protocol

Swift includes the Error protocol, which forms the basis of the error-handling architecture. Any type conforming to this protocol represents an error and can take part in error-handling routines you will learn about shortly.

Throwing Errors

What does your program do with these errors? It throws them, of course! That’s the terminology you’ll see: throwing errors and then catching them.

Handling Errors

After your program throws an error, you need to handle that error. There are two ways to approach this problem: Immediately handling your errors or bubble them up to another level.

Not Looking at the Detailed Error

If you don’t care about the error details, you can use try? to wrap the result of a function (or method) in an optional. The function will then return nil if an error is thrown within it. In this case, there is no need to set up a do {} catch {} block.

Stopping Your Program on an Error

Sometimes you know for sure that your code is not going to fail. For example, if you know the bakery is now open and just restocked the cookie jar, you can order a cookie. Add:

Typed Throws

Until now you have only seen a generic throws added to functions. It turns out it’s also possible to indicate what types of Error specifically can be thrown from a function. This helps because you can significantly narrow down the amount of cases needed to be handled. And after all, your Bakery is only going to throw BakeryErrors! It’s not like the Bakery can throw a CarError is it!

Advanced Error Handling

Cool, you know how to handle errors! That’s neat, but how do you scale your error handling to a more extensive, complex app?

PugBot

The sample project you’ll work with in this second half of the chapter is PugBot. The PugBot is cute and friendly but sometimes gets lost and confused.

Handling Multiple Errors

You might benefit from a function that can move the PugBot and handle errors by reporting what went wrong. Add the following code to your playground:

rethrows

A function that takes a throwing closure as a parameter has to choose: either catch every error or be a throwing function. Let’s say you want a utility function to perform a specific movement or set of movements several times in a row.

Throwable Properties

Types can have computed properties. Sometimes a computed property could fail to compute. In those cases, you want to be able to throw an error from the getter. This is possible only from read-only computed properties.

Throwable Subscripts

You can also throw errors from read-only subscripts. Add the following code to your playground:

Challenges

Before moving on, here are some challenges to test your error-handling knowledge. It’s best to try and solve them yourself, but solutions are available if you get stuck. These came with the download or are available at the printed book’s source code link listed in the introduction.

Challenge 1: Even Strings

Write a function that converts a String to an even number, rounding down if necessary. It should throw if the String is not a valid number.

Challenge 2: Safe Division

Write a function that divides two Ints. It should throw if the divisor is zero.

Challenge 3: Account Login

Given the following code:

Key Points

  • You can make an initializer failable by naming them init? and returning nil if they fail.
  • A type can conform to the Error protocol to work with Swift’s error-handling system.
  • Any function that can throw an error, or call a function that can throw an error, has to be marked with throws or rethrows.
  • A function can be marked as throwing a certain type of error by appending the error type in parentheses after the throws keyword.
  • When calling an error-throwing function from a function that doesn’t throw, you must embed the function call in a do block. Within that block, you try the function, and if it fails, you catch the error.
  • try? lets you convert a thrown error into a nil return value.
  • try! lets you convert a thrown error to a fatal error that terminates your app.
  • Read-only computed properties and subscripts can be annotated to throw. To access these properties, the standard try-catch rules apply.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now