Skip to content
Prepare to Grow

Swift Fundamentals

Error Handling

Represent recoverable failures with Error, throw, throws, do-catch, and defer.

Beginner5 min read2 guided activities

Before you begin

What you will understand

  • Define errors with an enum.
  • Throw and propagate recoverable failures.
  • Handle errors with do-catch.
  • Distinguish errors from optionals and programmer mistakes.
01

Learning stage

Concept Explanation

Swift error handling represents recoverable failures that a caller may need to understand. Any type conforming to Error can be thrown; enums work well when failure cases form a finite set.

A throwing function marks its contract with throws. Callers use try and can handle failures with do-catch, propagate them from another throwing function, convert them to optionals with try?, or deliberately assert with try! only when failure is impossible by design.

  • throw stops the current path and produces an error.
  • throws marks a function that can propagate an error.
  • do-catch handles matching errors.
  • defer schedules cleanup when the current scope exits.
02

Learning stage

Syntax & Examples

The validator throws distinct domain errors and the caller handles each one explicitly.

Enrollment.swiftswift
enum EnrollmentError: Error {
  case emptyName
  case courseFull
}

func enroll(name: String, availableSeats: Int) throws -> String {
  guard !name.isEmpty else { throw EnrollmentError.emptyName }
  guard availableSeats > 0 else { throw EnrollmentError.courseFull }
  return "Enrolled \(name)"
}

do {
  print(try enroll(name: "Mina", availableSeats: 1))
} catch EnrollmentError.emptyName {
  print("Enter your name")
} catch EnrollmentError.courseFull {
  print("The course is full")
} catch {
  print("Unexpected error: \(error)")
}
Expected output: “Enrolled Mina”. Other inputs take the matching catch branch.
03

Learning stage

Real-World Usage

These concepts appear throughout production iOS code. Focus on the requirement each technique communicates.

  • Report network, decoding, persistence, and validation failures with useful context.
  • Propagate failures through service layers until a boundary can decide how to recover or communicate.
  • Use defer for scope-bound cleanup such as releasing a temporary resource.
04

Learning stage

Common Mistakes

Notice these mistakes early so the compiler and type system can help instead of becoming obstacles.

  • Using errors for ordinary absence where an optional communicates the contract better.
  • Catching every error and discarding the reason.
  • Using try? when the difference between failure cases matters.
  • Using try! with input, network, or file operations that can genuinely fail.
05

Learning stage

Practice Exercises

Work through these activities in a small Xcode project. No embedded playground is required on this site.

Activity 1

Create validation errors

Define errors for an empty title and a title that is too long. Write a throwing validator and handle both cases.

Hint: Associated values can include useful context such as the maximum length.

Activity 2

Choose optional or error

For a dictionary lookup, a network request, and optional profile biography, decide whether Optional or throws communicates each result better.

Hint: Ask whether absence is expected or whether callers need a failure reason.

06

Learning stage

Knowledge Check

Answer each question before revealing the explanation.

QUESTION 1

What must a thrown value conform to?

  1. A.Error
  2. B.Equatable
  3. C.Codable
  4. D.Identifiable
Reveal answer

Error

Any type conforming to Error can participate in Swift's throwing system.

QUESTION 2

What does try? do when an error is thrown?

Reveal answer

It converts the result to an optional and produces nil for the failure.

Use it only when losing the specific error is acceptable.

07

Learning stage

Interview Preparation

Explain the idea in terms of its purpose, behavior, and tradeoffs rather than reciting syntax.

When should a Swift API return an optional versus throw an error?

Short answer: Use an optional for expected absence without needed detail; throw when failure reasons or recovery decisions matter.

Explore the detailed answer

An optional communicates value-or-no-value. A throwing API can communicate distinct failure cases and propagate them. The choice is part of the contract: callers should receive only the information they can use meaningfully.

Possible follow-ups

  • • How does try? change the contract?
  • • When is try! justified?
08

Learning stage

Key Takeaways

Errors communicate recoverable failure with context. Design failure contracts deliberately, preserve useful information, and handle errors at the layer that can make a meaningful decision.

  • Thrown values conform to Error.
  • throws makes failure part of a function contract.
  • do-catch handles or transforms failures.
  • Optionals and errors communicate different kinds of uncertainty.