Enumerations & Associated Values

Reviewed & published by Brayan K

Enums model a fixed set of possibilities and are far more powerful in Swift than in many languages. By the end of this lesson you'll define enums, attach raw and associated values, switch over cases exhaustively, and iterate with CaseIterable.

Part of the free Swift course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Defining Enums & Switching

Declare an enum with enum and list its cases. When the type is known, you can write just .north. A switch over an enum must be exhaustive — the compiler ensures you handle every case.

// An ENUM defines a fixed set of related, named cases.
enum Direction {
    case north
    case south
    case east
    case west
}

// Create a value. The type can be inferred, so .north is enough.
let heading: Direction = .north

// Switch over the cases — the compiler checks you handle them ALL.
switch heading {
case .north: print("Heading up")
case .south: print("Heading down")
case .east:  print("Heading right")
case .west:  print("Heading left")
}

2️⃣ Raw Values

Give cases a fixed underlying value by writing the raw type, e.g. enum Planet: Int. Read it with .rawValue, and create a case from a raw value with the failable init(rawValue:), which returns an optional.

// RAW VALUES give each case a fixed underlying value (Int, String, etc.).
enum Planet: Int {
    case mercury = 1, venus, earth, mars   // venus=2, earth=3, mars=4 (auto-increment)
}
print(Planet.earth.rawValue)          // 3

// String raw values default to the case name unless you set them.
enum Suit: String {
    case hearts, spades, clubs, diamonds
}
print(Suit.spades.rawValue)           // spades

// Create a case FROM a raw value — this can fail, so it's an OPTIONAL.
let maybe = Planet(rawValue: 4)        // Optional(Planet.mars)
print(maybe ?? .earth)                 // mars

let bad = Planet(rawValue: 99)         // nil — no such planet
print(bad == nil)                      // true

3️⃣ Associated Values

Associated values let each case carry extra data that can differ per instance. Extract that data in a switch with case let pattern binding.

// ASSOCIATED VALUES let each case carry extra, instance-specific data.
enum Barcode {
    case upc(Int, Int, Int, Int)        // four numbers
    case qrCode(String)                 // a string payload
}

let item = Barcode.upc(8, 85909, 51226, 3)
let ticket = Barcode.qrCode("ABCDEF")

// Extract the associated data in a switch with 'case let'.
func describe(_ code: Barcode) {
    switch code {
    case let .upc(a, b, c, d):
        print("UPC: \(a)-\(b)-\(c)-\(d)")
    case let .qrCode(text):
        print("QR: \(text)")
    }
}

describe(item)        // UPC: 8-85909-51226-3
describe(ticket)      // QR: ABCDEF

4️⃣ Iterating with CaseIterable

Conform to CaseIterable and Swift gives you allCases — every case in order. Ideal for menus, pickers, and validation.

// CaseIterable gives you 'allCases' — a collection of every case.
enum Weekday: String, CaseIterable {
    case mon, tue, wed, thu, fri
}

print(Weekday.allCases.count)          // 5

for day in Weekday.allCases {
    print(day.rawValue)                 // mon, tue, wed, thu, fri
}

// Great for building menus, pickers, or validating input.

Your turn. Fill in the blanks, then run it and check the output.

// 🎯 YOUR TURN — replace each ___ then run it in SwiftFiddle.

// 1) Define an enum 'Light' with cases red, yellow, green.
___ Light {                       // 👉 replace ___ with the keyword enum
    case red, yellow, green
}

// 2) Make a value set to .green (let the type be inferred).
let signal: Light = ___            // 👉 replace ___ with .green

// 3) Switch over it and print "Go" for green, "Stop" otherwise.
switch signal {
case .green: print("Go")
case .red, .yellow: print("Stop")
}

// ✅ Expected output:
//    Go

Pro Tips

Common Errors (and the fix)

📋 Quick Reference

TaskCodeResult
Defineenum D { case n, s }named cases
Uselet x: D = .ninferred type
Raw valuePlanet.earth.rawValue3
From rawPlanet(rawValue: 3)Planet? optional
Associatedcase qr(String)per-case data
All casesD.allCasesneeds CaseIterable

Mini-Challenge: Drawing Commands

Build it, run it, and check your output against the example in the comments.

// 🎯 MINI-CHALLENGE: Drawing commands
// 1. Define an enum 'Shape' with associated values:
//      case circle(radius: Double)
//      case rectangle(width: Double, height: Double)
// 2. Write a function area(_ s: Shape) -> Double that switches over the cases:
//      circle -> 3.14159 * radius * radius
//      rectangle -> width * height
// 3. Print the area of a circle(radius: 2) and a rectangle(width: 3, height: 4).
//
// ✅ Example output (approximately):
//    Circle area: 12.56636
//    Rectangle area: 12.0

// your code here

🎉 Lesson Complete!

Practice quiz

What keyword defines an enumeration in Swift?

  • enumeration
  • case
  • enum
  • type

Answer: enum. Enumerations are declared with the enum keyword.

What does an enum represent?

  • A fixed set of related, named cases
  • A list that can grow
  • A key-value map
  • An optional value

Answer: A fixed set of related, named cases. An enum defines a group of related values as named cases.

After `let d: Direction = .north`, what is `.north` short for?

  • north only
  • a String
  • a number
  • Direction.north

Answer: Direction.north. Swift infers the type, so .north means Direction.north.

What is a RAW VALUE in an enum?

  • A random number
  • A fixed underlying value (e.g. Int or String) tied to each case
  • An associated value
  • The case name only

Answer: A fixed underlying value (e.g. Int or String) tied to each case. Raw values are constant underlying values like Int or String attached to each case.

What does an ASSOCIATED VALUE let a case do?

  • Carry extra data that varies per instance
  • Store nothing
  • Become a class
  • Repeat itself

Answer: Carry extra data that varies per instance. Associated values let each case hold extra, instance-specific data.

Which raw-typed enum initializer can fail and returns an optional?

  • Direction(name:)
  • MyEnum.init()
  • MyEnum(rawValue:)
  • MyEnum.first

Answer: MyEnum(rawValue:). init(rawValue:) returns an optional because the raw value might not match any case.

What does conforming to CaseIterable provide?

  • A description property
  • An allCases collection of every case
  • Automatic raw values
  • JSON encoding

Answer: An allCases collection of every case. CaseIterable synthesizes allCases, a collection of all the enum's cases.

Why is a switch over an enum often safer than over an Int?

  • It's faster
  • It uses less memory
  • It avoids loops
  • The compiler requires you handle every case (exhaustiveness)

Answer: The compiler requires you handle every case (exhaustiveness). Switches over enums must be exhaustive, so the compiler catches missing cases.

How do you extract an associated value in a switch case?

  • case .point: x
  • case let .point(x, y):
  • case .point[x, y]:
  • you cannot

Answer: case let .point(x, y):. Bind associated values with patterns like case let .point(x, y).

If a raw-value enum has Int raw values starting implicitly, what is the first case's raw value by default?

  • 1
  • -1
  • 0
  • nil

Answer: 0. For an Int-backed enum, implicit raw values start at 0 and increment.

Continue this course

Frequently asked questions

What is an enum and why is it useful?

An enum (enumeration) defines a fixed set of related, named cases — like the four compass directions or the states of a traffic light. It makes invalid values impossible: a Direction can only ever be one of its cases. Combined with switch, the compiler forces you to handle every case, catching bugs at compile time rather than runtime.

What is the difference between a raw value and an associated value?

A raw value is a fixed, constant underlying value (such as an Int or String) attached to each case at definition time — every .earth always has raw value 3, for example. An associated value is extra data attached when you create a particular value, and it can differ each time: case qrCode(String) lets one QR code carry "ABC" and another carry "XYZ". A case can have one or the other, not both.

Why does init(rawValue:) return an optional?

Because the raw value you pass might not correspond to any case. Planet(rawValue: 99) has no matching planet, so it returns nil rather than crashing. That's why the result type is Planet? — you unwrap it with if let or supply a default with ??, just like any other optional.

How do I read an associated value back out?

Use a switch with pattern matching and bind the values: case let .qrCode(text) gives you text inside that branch, and case let .upc(a, b, c, d) binds all four numbers. You can also use if case let for a single case. The bound names are then plain values you can use normally.

What does CaseIterable do?

Conforming an enum to CaseIterable makes Swift synthesize a static allCases property — a collection containing every case in declaration order. It's perfect for building menus and pickers, iterating over all options, or counting how many cases exist, without manually listing them and risking falling out of sync.

Related lessons