How to Use Try Catch in Swift

Use do-catch in Swift when code can throw errors that need graceful handling instead of crashing. This is essential for file operations, JSON parsing, network layers, and validation workflows.

What you’ll build or solve

You’ll learn how to use do, try, and catch in Swift with throwing functions, custom errors, and typed pattern matching. You’ll also know when try? is cleaner.

When this approach works best

This approach is the right choice when failure is expected and the app should recover.

Common real-world scenarios include:

  • File loading
  • JSON decoding
  • Validation logic
  • Network parsing
  • Local data persistence

This is a bad idea when the error should intentionally bubble to a higher layer.

Prerequisites

You only need:

  • Basic Swift functions
  • Familiarity with throws
  • Understanding of enums

Step-by-step instructions

Step 1: Create a throwing function

Throwing functions use throws.

enum LoginError: Error {
    case invalidCredentials
}

func login(password: String) throws {
    if password != "secret" {
        throw LoginError.invalidCredentials
    }
}

This makes failure explicit.

Step 2: Call it with do-catch

Use try inside a do block.

do {
    try login(password: "wrong")
    print("Logged in")
} catch {
    print("Login failed")
}

This safely catches the thrown error.

Step 3: Match specific error cases

Catch specific cases when needed.

do {
    try login(password: "wrong")
} catch LoginError.invalidCredentials {
    print("Wrong password")
}

This creates precise recovery behavior.

Step 4: Use try? for optional fallback

For lightweight failure handling, use try?.

let result = try? login(password: "wrong")

This converts failure into nil.

What to look for:

  • Throwing functions use throws
  • do-catch handles recoverable failures
  • Pattern matching catches specific errors
  • try? converts errors into nil
  • Great for decoding and validation

Examples you can copy

File decode

let user = try decoder.decode(User.self, from: data)

Optional parse

let config = try? loadConfig()

Validation catch

catch ValidationError.invalidEmail

Common mistakes and how to fix them

Mistake 1: Forgetting try

What the reader might do:

login(password: "secret")

Why it breaks: Swift requires explicit error acknowledgment.

Corrected approach:

Use try.

Mistake 2: Catching too broadly

What the reader might do:

Only use generic catch.

Why it breaks: specific recovery paths get lost.

Corrected approach:

Match important error cases first.

Mistake 3: Overusing try?

What the reader might do:

Use try? everywhere.

Why it breaks: real error context disappears.

Corrected approach:

Use full do-catch when debugging or recovery matters.

Troubleshooting

If the compiler errors, add try.

If the wrong catch block runs, check error pattern order.

If debugging is hard, avoid try?.

If the error should bubble upward, mark the caller as throws.

Quick recap

  • Use throws for failing functions
  • Use do-catch for recovery
  • Match specific error cases
  • Use try? for optional fallback
  • Prefer explicit recovery when context matters