Skip to content

Chapter 6 of 7

Error Handling and Control Flow

Swift uses a do-try-catch model for error handling that integrates well with the type system. Functions that can fail are marked with the throws keyword, and callers must explicitly handle the possibility of an error using try inside a do block, followed by catch clauses that match specific error types. A general catch clause can catch any remaining errors. Custom error types are typically defined as enums conforming to the Error protocol, with cases that can optionally carry associated values for additional context, such as case serverError(code: Int).

Swift provides three variants of try for different situations. The standard try requires the call to be inside a do-catch block so errors are explicitly handled. The try? variant converts the result into an optional, returning nil if an error is thrown, which is convenient when the caller only cares whether the call succeeded. The try! variant force-tries the call and crashes at runtime if an error is thrown, so it should only be used when an error is impossible. The rethrows keyword is used in functions whose only throwing behavior comes from a closure parameter; the function will only throw if the passed closure throws, otherwise callers do not need to use try.

Control flow in Swift is enhanced by two important statements. The guard statement requires a condition to be true to continue execution, and its else branch must exit the current scope through return, throw, break, or a similar mechanism. When used to unwrap an optional, the unwrapped value is available either only within the if block (with if let) or in the rest of the enclosing scope (with guard let), making guard let the preferred pattern for early exits. The defer statement, by contrast, runs a block of code just before the current scope exits, regardless of how it exits, which is useful for cleanup such as closing files. Multiple defer blocks within the same scope execute in reverse order of declaration, like a stack.

All chapters
  1. 1Optionals and Safe Unwrapping
  2. 2Protocols and Extensions
  3. 3Closures and Functional Patterns
  4. 4Types: Structs, Classes, and Enums
  5. 5Generics and Type Abstraction
  6. 6Error Handling and Control Flow
  7. 7Memory Management, Properties, and Advanced Features

Drill it

Reading is not remembering. These come from the Swift Programming deck:

Q

What is an Optional in Swift?

An Optional in Swift represents a variable that can hold either a value or nil. It is declared using a ? after the type, e.g., var name: String?. Optionals enfo...

Q

How do you unwrap an Optional using if let?

You use optional binding with if let:if let unwrapped = optionalValue {  print(unwrapped)}This safely unwraps the optional and binds its value to a ne...

Q

What is the difference between Optional chaining and forced unwrapping?

Optional chaining uses ?. and returns nil if the optional is nil, failing gracefully.Forced unwrapping uses ! and crashes at runtime if the optional is nil.Exam...

Q

What is the nil-coalescing operator in Swift?

The nil-coalescing operator ?? provides a default value when an optional is nil.Example: let name = optionalName ?? "Unknown"If optionalName is nil, name is set...