Enums in Swift: Associated Values, Raw Values, and Pattern Matching
Every character in Toy Story is a distinct type — Woody is an action figure, Rex is a stuffed dinosaur, RC is a remote-controlled car. They’re all toys, but each one carries different data and behaves differently. Swift’s enumerations (enums) let you model exactly this: a fixed set of related cases, each optionally carrying its own data.
In this guide, you’ll learn how to define enums, use raw values and associated values, add methods and computed
properties, iterate with CaseIterable, and combine enums with switch for powerful pattern matching. We won’t cover
generics or recursive enums — those come later in the series.
What You’ll Learn
- What Is an Enum?
- Raw Values
- Associated Values
- Methods and Computed Properties
- CaseIterable
- Pattern Matching with Switch
- Common Mistakes
- What’s Next?
What Is an Enum?
An enumeration (or enum) defines a type with a fixed set of related values called cases. Unlike a String
or Int that can hold anything, an enum restricts values to only the ones you define.
Think of it like the toy categories in Andy’s room. A toy is either an action figure, a stuffed animal, or a vehicle — there’s no mystery fifth option:
enum ToyType {
case action
case stuffed
case vehicle
}
let woody: ToyType = .action
let rex: ToyType = .stuffed
print(woody)
print(rex)
action
stuffed
The keyword enum declares the type. Each case is one possible value. Once Swift knows the type, you can use the
shorthand dot syntax (.action instead of ToyType.action).
Tip: Enum case names use
lowerCamelCasein Swift, while the enum type itself usesUpperCamelCase. This follows Swift’s naming conventions.
Raw Values
You can assign a raw value to each case — a default value of type String, Int, or any type conforming to
RawRepresentable. This is useful when you need a consistent underlying value for each case.
Integer Raw Values
When you use Int raw values, Swift auto-increments starting from 0 (or from whatever value you specify):
enum PixarMovie: Int {
case toyStory = 1
case aBugsLife // 2
case toyStory2 // 3
case monstersInc // 4
case findingNemo // 5
}
let movie = PixarMovie.findingNemo
print(movie.rawValue)
5
String Raw Values
With String raw values, Swift uses the case name as the default value:
enum Character: String {
case woody = "Sheriff Woody"
case buzz = "Buzz Lightyear"
case jessie = "Jessie the Cowgirl"
}
print(Character.buzz.rawValue)
Buzz Lightyear
Creating from a Raw Value
You can go the other direction — create an enum from a raw value. This returns an optional because the raw value might not match any case:
let maybe = PixarMovie(rawValue: 3)
print(maybe as Any)
let nope = PixarMovie(rawValue: 99)
print(nope as Any)
Optional(PixarMovie.toyStory2)
nil
The init?(rawValue:) is a failable initializer — it returns nil when no case matches. If you haven’t learned
about optionals yet, check out Optionals in Swift.
Associated Values
While raw values give every case the same type of data, associated values let each case carry different data. This is where Swift enums become far more powerful than enums in most other languages.
Imagine modeling Toy Story characters where each type carries unique information:
enum ToyCharacter {
case cowboy(catchphrase: String)
case spaceRanger(jetpackFuel: Double)
case dinosaur(scareLevel: Int)
}
let woody = ToyCharacter.cowboy(catchphrase: "There's a snake in my boot!")
let buzz = ToyCharacter.spaceRanger(jetpackFuel: 87.5)
let rex = ToyCharacter.dinosaur(scareLevel: 2)
print(woody)
print(buzz)
cowboy(catchphrase: "There\'s a snake in my boot!")
spaceRanger(jetpackFuel: 87.5)
Each case stores completely different data. A cowboy has a catchphrase (String), a spaceRanger has fuel level
(Double), and a dinosaur has a scare level (Int). You extract these values using pattern matching (covered below).
Warning: A single enum can use either raw values or associated values, not both. If you need both, use associated values and add a computed property for any fixed data.
Methods and Computed Properties
Swift enums aren’t just passive lists — they can have methods and computed properties, just like structs and classes.
Computed Properties
A computed property calculates a value on the fly rather than storing it:
enum Villain: String {
case zurg = "Emperor Zurg"
case lotso = "Lots-o'-Huggin' Bear"
case gabbyGabby = "Gabby Gabby"
var description: String {
"Villain: \(self.rawValue)"
}
}
print(Villain.lotso.description)
Villain: Lots-o'-Huggin' Bear
Methods
Enums can also define full methods:
enum Emotion {
case joy, sadness, anger, fear, disgust
func theme() -> String {
switch self {
case .joy: return "Yellow and bright!"
case .sadness: return "Blue and tearful"
case .anger: return "Red and fiery"
case .fear: return "Purple and shaky"
case .disgust: return "Green and sassy"
}
}
}
print(Emotion.joy.theme())
print(Emotion.anger.theme())
Yellow and bright!
Red and fiery
The switch self pattern inside an enum method is very common — it lets each case define its own behavior.
CaseIterable
When you need to loop through all cases of an enum, conform to the CaseIterable protocol. Swift will automatically
generate an allCases array:
enum PixarStudio: String, CaseIterable {
case toyStory = "Toy Story"
case findingNemo = "Finding Nemo"
case theIncredibles = "The Incredibles"
case coco = "Coco"
case soul = "Soul"
}
for studio in PixarStudio.allCases {
print(studio.rawValue)
}
Toy Story
Finding Nemo
The Incredibles
Coco
Soul
You also get a count for free:
print("Total: \(PixarStudio.allCases.count) movies")
Total: 5 movies
Note:
CaseIterableonly works when the enum has no associated values. Associated values make each case potentially infinite (anyString, anyDouble, etc.), so Swift can’t enumerate them.
Pattern Matching with Switch
Enums and switch are natural partners. Swift requires switch statements on enums to be exhaustive — you must
handle every case, or provide a default:
let toy = ToyType.vehicle
switch toy {
case .action:
print("To infinity and beyond!")
case .stuffed:
print("Roar! ...Was that scary?")
case .vehicle:
print("Vroom vroom!")
}
Vroom vroom!
Extracting Associated Values
Use let bindings inside case patterns to extract associated values:
let character = ToyCharacter.cowboy(catchphrase: "There's a snake in my boot!")
switch character {
case .cowboy(let catchphrase):
print("Cowboy says: \(catchphrase)")
case .spaceRanger(let fuel):
print("Fuel remaining: \(fuel)%")
case .dinosaur(let level):
print("Scare level: \(level)/10")
}
Cowboy says: There's a snake in my boot!
Using where Clauses
Add a where clause to match cases conditionally:
let buzz = ToyCharacter.spaceRanger(jetpackFuel: 15.0)
switch buzz {
case .spaceRanger(let fuel) where fuel < 20:
print("Warning: Low fuel! Only \(fuel)% left")
case .spaceRanger(let fuel):
print("Fuel level healthy: \(fuel)%")
default:
print("Not a space ranger")
}
Warning: Low fuel! Only 15.0% left
Apple Docs:
Enumerations— The Swift Programming Language
Common Mistakes
Non-Exhaustive Switch Without Default
Swift requires you to handle every case. If you miss one, the compiler will stop you:
// ❌ Won't compile — missing cases
enum Direction {
case north, south, east, west
}
let heading = Direction.north
// switch heading {
// case .north: print("Going north")
// case .south: print("Going south")
// }
// Error: Switch must be exhaustive
// ✅ Handle all cases or add default
let heading = Direction.north
switch heading {
case .north: print("Going north")
case .south: print("Going south")
case .east: print("Going east")
case .west: print("Going west")
}
Tip: Prefer listing all cases explicitly over using
default. That way, if you add a new case later, the compiler will warn you everywhere you need to handle it.
Confusing Raw Values with Associated Values
Raw values are fixed at definition time and every case has the same type. Associated values are provided when you create an instance and each case can carry different types:
// ❌ Confusing the two concepts
// Raw value — fixed, same type for every case
enum Planet: Int {
case mercury = 1
case venus = 2
}
// Planet.mercury always has rawValue 1
// Associated value — set at creation, different per case
enum Delivery {
case standard(days: Int)
case express(hours: Int)
case drone(altitude: Double)
}
// Each Delivery instance carries its own data
// ✅ Remember: raw values are fixed defaults,
// associated values are instance-specific data
let order1 = Delivery.standard(days: 5)
let order2 = Delivery.express(hours: 2)
// Each carries different data set at creation time
What’s Next?
- Enums define a type with a fixed set of related cases.
- Raw values assign a default underlying value (
Int,String) to each case. - Associated values let each case carry different custom data.
- Enums can have computed properties and methods.
CaseIterablegives you anallCasesarray for free.switchpattern matching extracts associated values and must be exhaustive.
Now that you can model distinct categories with enums, it’s time to learn how to group related data and behavior together. Head to Structs vs Classes to understand value types, reference types, and when to use each.