Swift Switch

Swift's switch statement matches a value against multiple patterns and, unlike C-based languages, never falls through to the next case by default.

Basic Switch Syntax

A switch statement compares a value against a series of cases and executes the body of the first matching one. Every switch in Swift must be exhaustive, meaning it must cover every possible value of the type being matched — for types with an unbounded set of values, such as Int or String, you satisfy this with a default case.

A basic switch over a String

let fruit = "apple"

switch fruit {
case "apple":
    print("An apple a day...")
case "banana":
    print("Great source of potassium")
default:
    print("Unknown fruit")
}
// Prints: An apple a day...

No Implicit Fallthrough

In C, Java, and JavaScript, each case falls through to the next unless you write break. Swift reverses this default: once a matching case's body finishes, the switch exits immediately, and you never need break. If you genuinely want fallthrough behavior, Swift lets you opt in explicitly with the fallthrough keyword.

Explicit fallthrough when you need it

let letterGrade = "B"

switch letterGrade {
case "A":
    print("Excellent")
    fallthrough
case "B":
    print("Good job")
    fallthrough
case "C":
    print("Passing")
default:
    print("Needs improvement")
}
// Prints:
// Good job
// Passing

Matching Ranges, Tuples, and Multiple Values

Swift's switch statement is far more expressive than a simple equality check. A single case can match multiple values separated by commas, match against a range using the closed or half-open range operators, or destructure a tuple, matching each component independently. Combined with where clauses, cases can add extra conditional filtering on top of pattern matching.

  • case 1, 3, 5, 7, 9: matches any of several discrete values in one case
  • case 0..<18: matches any value that falls inside a range
  • case (let x, let y) where x == y: destructures a tuple and adds a condition
  • case let value: binds the matched value to a new constant for use in the body
  • default: is required whenever the cases don't already cover every possibility

Ranges, tuples, and where clauses

let age = 45

switch age {
case 0..<13:
    print("Child")
case 13..<20:
    print("Teenager")
case 20..<65:
    print("Adult")
default:
    print("Senior")
}
// Prints: Adult

let point = (3, 3)

switch point {
case (0, 0):
    print("Origin")
case (let x, let y) where x == y:
    print("On the diagonal at \(x)")
default:
    print("Somewhere else")
}
// Prints: On the diagonal at 3

Switching on Enums

switch pairs especially well with enum types, since the compiler already knows every possible case an enum can take. If you cover all enum cases explicitly, Swift does not even require a default clause, and if you later add a new case to the enum, the compiler will flag every switch statement that needs updating.

Exhaustive switch over an enum

enum Direction {
    case north, south, east, west
}

let heading = Direction.east

switch heading {
case .north:
    print("Heading up")
case .south:
    print("Heading down")
case .east:
    print("Heading right")
case .west:
    print("Heading left")
}
// Prints: Heading right
Note: When a switch covers every case of an enum, resist the temptation to add a catch-all default — an exhaustive switch gives you a free compile error whenever a new enum case is introduced, which is a powerful safety net during refactors.
Note: Each case's body must contain at least one statement. An empty case is a compile-time error in Swift, so if you intentionally want to do nothing for a case, write break explicitly.
FeatureSwift switchC-style switch
Falls through by defaultNoYes
Requires break per caseNoYes
Can match rangesYesNo
Can match tuplesYesNo
Must be exhaustiveYesNo

Exercise: Swift Switch

Does Swift's `switch` fall through to the next case automatically, like C does?