Menu
Coddy logo textTech

do, try, catch

Part of the Logic & Flow section of Coddy's Swift journey — lesson 45 of 56.

The full form for handling errors is do/try/catch:

enum DivError: Error { case byZero }

func divide(_ a: Int, _ b: Int) throws -> Int {
    if b == 0 { throw DivError.byZero }
    return a / b
}

do {
    let r = try divide(10, 2)
    print(r)                      // 5
} catch DivError.byZero {
    print("can't divide by zero")
} catch {
    print("unknown error")
}

try goes in front of any throwing call. If the call throws, control jumps to the matching catch; otherwise execution falls through past the do block.

Multiple catch clauses run top-to-bottom and the first match wins, just like a switch. The bare catch at the end is the catch-all, you almost always want one to keep the compiler happy.

challenge icon

Challenge

Easy

Define an enum ParseError: Error with three cases: empty, notInteger, and negative.

Define a throwing function parsePositive(_ s: String) throws -> Int that:

  • Throws .empty when s trimmed of whitespace is empty
  • Throws .notInteger when s can't be parsed as Int
  • Throws .negative when the parsed value is < 0
  • Otherwise returns the parsed value

Read a single line from stdin and call parsePositive in a do/catch block. Print:

  • got: <n> on success
  • error: empty, error: not integer, or error: negative for each case

For input 42, the output is got: 42. For an empty line, it's error: empty. For abc it's error: not integer.

Cheat sheet

Swift error handling uses do/try/catch. Define errors with an enum conforming to Error, mark throwing functions with throws, and use throw to raise an error:

enum DivError: Error { case byZero }

func divide(_ a: Int, _ b: Int) throws -> Int {
    if b == 0 { throw DivError.byZero }
    return a / b
}

do {
    let r = try divide(10, 2)
    print(r)                      // 5
} catch DivError.byZero {
    print("can't divide by zero")
} catch {
    print("unknown error")        // catch-all
}
  • try must precede every throwing call.
  • catch clauses are matched top-to-bottom; first match wins.
  • A bare catch at the end acts as a catch-all.

Try it yourself

let line = readLine()!

// TODO: enum ParseError; func parsePositive(_:) throws -> Int;
// do/try/catch with three branches plus the catch-all
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Logic & Flow