Skip to main content

Swift Switch Case

Introduction

The switch statement is a powerful control flow mechanism in Swift that allows you to compare a value against multiple possible matching patterns. It's an alternative to if-else statements that is particularly useful when you need to check a value against many possible conditions. Unlike switch statements in other languages, Swift's version is much more versatile and type-safe, with features like pattern matching, value binding, and the absence of implicit fallthrough.

Basic Syntax

The basic syntax of a Swift switch statement looks like this:

swift
switch valueToCheck {
case pattern1:
// code to execute if value matches pattern1
case pattern2, pattern3:
// code to execute if value matches pattern2 or pattern3
default:
// code to execute if no patterns match
}

Let's see this in action with a simple example:

swift
let someCharacter: Character = "z"

switch someCharacter {
case "a":
print("The first letter of the alphabet")
case "z":
print("The last letter of the alphabet")
default:
print("Some other character")
}

// Output: The last letter of the alphabet

Key Features of Swift Switch Statements

1. Exhaustiveness

Swift requires that your switch statements are exhaustive, meaning they must cover all possible values of the type being checked, or include a default case:

swift
let anotherCharacter: Character = "a"

switch anotherCharacter {
case "a", "A":
print("The letter A")
case "b", "B":
print("The letter B")
case "c", "C":
print("The letter C")
default:
print("Some other character")
}

// Output: The letter A

2. No Implicit Fallthrough

Unlike C and other languages, Swift doesn't fall through to the next case by default. Once a case is matched and executed, the switch statement completes without checking any other cases:

swift
let number = 5

switch number {
case 5:
print("The number is 5")
// No need for break statement
case 6:
print("The number is 6")
default:
print("The number is neither 5 nor 6")
}

// Output: The number is 5

3. Range Matching

Swift allows matching ranges of values in switch cases:

swift
let approximateCount = 62

switch approximateCount {
case 0:
print("No items")
case 1..<5:
print("A few items")
case 5..<12:
print("Several items")
case 12..<100:
print("Dozens of items")
case 100..<1000:
print("Hundreds of items")
default:
print("Many items")
}

// Output: Dozens of items

4. Tuple Pattern Matching

Switch cases can match against tuples to test multiple values:

swift
let point = (2, 0)

switch point {
case (0, 0):
print("Origin")
case (_, 0):
print("On the x-axis")
case (0, _):
print("On the y-axis")
case (-2...2, -2...2):
print("Inside the box")
default:
print("Outside the box")
}

// Output: On the x-axis

5. Value Binding

You can bind part of the matched value to a constant or variable for use within the case's body:

swift
let anotherPoint = (2, 0)

switch anotherPoint {
case (let x, 0):
print("On the x-axis with an x value of \(x)")
case (0, let y):
print("On the y-axis with a y value of \(y)")
case let (x, y):
print("Somewhere else at (\(x), \(y))")
}

// Output: On the x-axis with an x value of 2

6. Where Clauses

You can use where clauses to check for additional conditions:

swift
let yetAnotherPoint = (1, -1)

switch yetAnotherPoint {
case let (x, y) where x == y:
print("On the line x = y")
case let (x, y) where x == -y:
print("On the line x = -y")
case let (x, y):
print("At the point (\(x), \(y))")
}

// Output: On the line x = -y

7. Compound Cases

Multiple patterns can be combined into a single case, separated by commas:

swift
let someCharacter2: Character = "e"

switch someCharacter2 {
case "a", "e", "i", "o", "u":
print("\(someCharacter2) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter2) is a consonant")
default:
print("\(someCharacter2) is not a vowel or consonant")
}

// Output: e is a vowel

Practical Examples

Example 1: Game State Management

swift
enum GameState {
case start
case playing
case paused
case gameOver
}

func handleGameState(_ state: GameState) {
switch state {
case .start:
print("Game is starting. Loading resources...")
// Initialize game resources
case .playing:
print("Game is in progress. Update game elements.")
// Update game elements
case .paused:
print("Game is paused. Show pause menu.")
// Display pause menu
case .gameOver:
print("Game over. Show final score and options.")
// Show game over screen
}
}

let currentState = GameState.paused
handleGameState(currentState)

// Output: Game is paused. Show pause menu.

Example 2: HTTP Response Handler

swift
enum HTTPResponse {
case success(Int, String)
case error(Int, String)
case redirect(Int, String)
}

func handleResponse(_ response: HTTPResponse) {
switch response {
case .success(let code, let message):
print("Success with code \(code): \(message)")
// Process successful response
case .error(let code, _) where code >= 500:
print("Server error \(code)")
// Handle server error
case .error(let code, let message):
print("Client error \(code): \(message)")
// Handle client error
case .redirect(let code, let location):
print("Redirect \(code) to \(location)")
// Follow redirect
}
}

let successResponse = HTTPResponse.success(200, "OK")
handleResponse(successResponse)
// Output: Success with code 200: OK

let serverError = HTTPResponse.error(500, "Internal Server Error")
handleResponse(serverError)
// Output: Server error 500

Example 3: Calculator Application

swift
enum Operation {
case addition
case subtraction
case multiplication
case division
}

func calculate(_ a: Double, _ b: Double, operation: Operation) -> Double? {
switch operation {
case .addition:
return a + b
case .subtraction:
return a - b
case .multiplication:
return a * b
case .division:
if b == 0 {
return nil // Cannot divide by zero
}
return a / b
}
}

if let result = calculate(10, 5, operation: .division) {
print("Result: \(result)")
} else {
print("Invalid operation")
}

// Output: Result: 2.0

Common Pitfalls and Best Practices

1. Always Ensure Exhaustiveness

Swift requires your switch statements to be exhaustive. Either include all possible cases or use a default case:

swift
enum Compass {
case north, south, east, west
}

let direction = Compass.west

switch direction {
case .north:
print("Heading north")
case .south:
print("Heading south")
case .east:
print("Heading east")
case .west:
print("Heading west")
}
// This works because all cases are covered

// If we add a new case to Compass but don't update this switch,
// the compiler will generate an error

2. Avoid Empty Cases

If a case doesn't need to execute any code, you should explicitly declare it:

swift
switch someValue {
case valueA:
doSomething()
case valueB:
break // Explicitly do nothing
default:
doSomethingElse()
}

3. Use Fallthrough Intentionally

If you need fallthrough behavior, Swift provides the fallthrough keyword:

swift
let integerToDescribe = 5

switch integerToDescribe {
case 5:
print("The number is 5")
fallthrough
case 6:
print("The number is 5 or 6") // This will also execute when the case is 5
default:
print("The number is neither 5 nor 6")
}

// Output:
// The number is 5
// The number is 5 or 6

Summary

The Swift switch statement is a powerful control flow mechanism that offers:

  • Exhaustiveness checking for safety
  • No implicit fallthrough between cases
  • Pattern matching with ranges, tuples, and value binding
  • Additional condition checking with where clauses
  • Multiple patterns in a single case

Its versatility makes it preferable to lengthy if-else chains in many scenarios, particularly when dealing with multiple conditions or pattern matching.

Exercises

  1. Create a switch statement that categorizes temperatures as "freezing" (below 32°F), "cold" (32-50°F), "mild" (51-70°F), "warm" (71-90°F), or "hot" (above 90°F).

  2. Write a function that takes a tuple containing coordinates (x, y) and uses a switch statement to determine which quadrant the point falls in (or if it's on an axis).

  3. Create an enum representing different types of vehicles (car, truck, motorcycle, bicycle) and write a switch statement that returns the number of wheels for each type.

  4. Write a function that uses a switch statement with value binding to extract and process information from different kinds of optionals.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)