Reading — step 1 of 7
Learn
Swift enums are far more powerful than the C-style enums most languages have. They support associated values, raw values, methods, and rich pattern matching. The Swift Programming Language book treats them as foundational data modeling.
Basic enum
enum Direction {
case north
case south
case east
case west
}
let d = Direction.north
// or:
let e: Direction = .south // type inferred, shorthand
switch d {
case .north: print("up")
case .south: print("down")
case .east, .west: print("sideways")
}
The compiler ENFORCES exhaustive switch — miss a case and you get a compile error. Add new cases to the enum and every switch lights up — refactor-safe.
Associated values — Swift's killer feature
Each case can carry typed payload data:
enum Result {
case success(value: Int)
case failure(message: String)
}
let r = Result.success(value: 42)
switch r {
case .success(let value):
print("got \(value)")
case .failure(let message):
print("error: \(message)")
}
This is how Swift expresses sum types — a value is exactly one of several alternatives, each with its own data. Cleaner than:
- A class hierarchy (overkill for a closed set)
- An object with optional fields (every read needs to check)
- Discriminated unions in TypeScript (similar idea, different syntax)
Real-world example — JSON parsing:
enum JSONValue {
case null
case bool(Bool)
case number(Double)
case string(String)
case array([JSONValue])
case object([String: JSONValue])
}
A single type representing all JSON shapes, with the compiler's help to handle every case.
Raw values
For enums where each case has a fixed underlying value (Int, String, etc.):
enum Status: String {
case active = "active"
case archived = "archived"
case pending = "pending"
}
let s = Status.active
print(s.rawValue) // "active"
let s2 = Status(rawValue: "archived") // Status?
Status(rawValue:) is a failable initializer — returns nil for unknown values. Useful for parsing strings into typed enums.
For Int raw values, Swift auto-numbers from 0:
enum Priority: Int {
case low = 1
case medium
case high // = 3, auto-incremented
}
Methods on enums
enum CompassPoint {
case north, south, east, west
func opposite() -> CompassPoint {
switch self {
case .north: return .south
case .south: return .north
case .east: return .west
case .west: return .east
}
}
}
CompassPoint.north.opposite() // .south
Enums can also have computed properties, static methods, and even mutating methods that change self.
Pattern matching
Swift's switch and if case go far beyond simple equality:
// Range matching:
let score = 85
switch score {
case 0..<60: print("F")
case 60..<70: print("D")
case 70..<80: print("C")
case 80..<90: print("B")
case 90...100: print("A")
default: print("invalid")
}
// Tuple matching:
let point = (2, 0)
switch point {
case (0, 0): print("origin")
case (_, 0): print("on x-axis")
case (0, _): print("on y-axis")
case let (x, y): print("at \(x), \(y)")
}
// where clauses:
switch (x, y) {
case let (a, b) where a == b: print("on diagonal")
case let (a, b) where a > 0 && b > 0: print("first quadrant")
default: print("elsewhere")
}
// if case for single-pattern matching:
let maybeNum: Int? = 5
if case let .some(value) = maybeNum {
print("got \(value)")
}
Recursive enums (indirect)
For tree-shaped data:
indirect enum Tree {
case leaf(Int)
case node(left: Tree, right: Tree)
}
let t = Tree.node(
left: .leaf(1),
right: .node(left: .leaf(2), right: .leaf(3))
)
indirect lets a case reference the enum itself (otherwise infinite size). Use for trees, lists, expression ASTs.
Common mistakes
- Using an enum when a struct fits better — if you find yourself with one case carrying many fields, consider a struct.
- Forgetting exhaustive switch — covering with
default:works but loses the compile-time check when you add a new case. - Confusing raw values with associated values — raw values are static metadata; associated values vary per instance.
- Mutating an enum without
mutating— methods that change self need the keyword. - Comparing enums with associated values via == — only works if you implement Equatable (Swift does it automatically for enums where all associated values are Equatable in Swift 4.1+).
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…