- July 26, 2025
- Mins Read
An enumeration (or enum) in Swift defines a common type for a group of related values, and enables you to work with those values in a type-safe way.
// Basic enum with no raw values
enum CompassPoint {
case north
case south
case east
case west
}
// Shorthand: multiple cases on one line
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
enum
keyword introduces the type.case
defines one of the possible values.You can associate each case with a raw value (of type String
, Int
, etc.), which lets you convert between the enum and its underlying value.
enum Weekday: Int {
case monday = 1, tuesday, wednesday, thursday, friday, saturday, sunday
}
enum Direction: String {
case north = "N", south = "S", east = "E", west = "W"
}
// Implicit raw-value incrementing for integers, and implicit string raw-values matching case names:
enum Fruit: String {
case apple, banana, cherry
}
// Fruit.banana.rawValue == "banana"
init?(rawValue:)
.A switch
on an enum is exhaustive, so you must cover all cases (or include a default
).
let direction: CompassPoint = .west
switch direction {
case .north:
print("Heading north")
case .south:
print("Heading south")
case .east:
print("Heading east")
case .west:
print("Heading west")
}
Key points:
switch
already knows the type (.west
instead of CompassPoint.west
).switch direction {
case .north, .south:
print("Moving vertically")
case .east, .west:
print("Moving horizontally")
}
To loop over all cases of an enum, your type must conform to the CaseIterable
protocol:
enum Beverage: CaseIterable {
case coffee, tea, juice, water
}
for drink in Beverage.allCases {
print(drink)
}
// Prints: coffee, tea, juice, water
: CaseIterable
to the enum definition.allCases
array.let randomBeverage = Beverage.allCases.randomElement()!
Associated values let each case carry its own custom data—think of them like lightweight unions or tagged payloads.
enum Barcode {
case upc(Int, Int, Int, Int) // tuple of four Ints
case qrCode(String) // one String
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
Use a switch
to bind and extract:
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case .qrCode(let code):
print("QR code: \(code)")
}
let
:
case let .upc(numberSystem, manufacturer, product, check):
_
:
case let .upc(_, manufacturer, product, _):
print("Manufacturer: \(manufacturer), product: \(product)")
You can name the elements to improve readability:
enum Measurement {
case weight(kg: Double)
case age(years: Int)
}
let m = Measurement.weight(kg: 68.5)
switch m {
case .weight(kg: let w):
print("Weight: \(w) kg")
case .age(years: let y):
print("Age: \(y) years")
}
While you can’t mix raw values and associated values on the same enum directly, you can simulate it by using init?(rawValue:)
or custom initializers and computed properties.
Imagine you’re parsing messages from a server, where each message can be text, an image with a URL, or a reaction:
enum ChatMessage: CaseIterable {
case text(String)
case image(url: URL, thumbnailURL: URL)
case reaction(emoji: String, toMessageID: Int)
}
// Iterating all possible message "types" (for analytics, UI tabs, etc.):
for type in ChatMessage.allCases {
print("Supported type: \(type)")
}
// Handling an incoming message:
func handle(_ message: ChatMessage) {
switch message {
case .text(let content):
showText(content)
case let .image(url, thumbnail):
showImage(from: url, placeholder: thumbnail)
case .reaction(let emoji, let messageID):
addReaction(emoji, to: messageID)
}
}
This pattern keeps your code:
switch
statements needing updates.Feature | Syntax / Notes |
---|---|
Declaration | enum Name { case a, b, c } |
Raw values | enum E: Int { case one = 1, two, three } / enum S: String { case foo = "foo" } |
Associated values | case foo(Int, String) / case bar(name: String, age: Int) |
Switch matching | switch value { case .foo(let x, let y): … case .bar: … } |
Combining cases | case .a, .b: … |
CaseIterable | enum E: CaseIterable { … } → E.allCases |
Failable raw-value init | let e = E(rawValue: 2) returns E? |
Implicit init for String raw | enum X: String { case a, b } → X.a.rawValue == "a" |
Ignoring values | case .foo(_, let important, _) |
Binding multiple | case let .foo(x, y, z): |
NavigationKit is a lightweight library which makes SwiftUI navigation super easy to use. 💻 Installation 📦 Swift Package Manager Using Swift Package Manager, add ...
An alternative SwiftUI NavigationView implementing classic stack-based navigation giving also some more control on animations and programmatic navigation. NavigationStack Installation ...
With SwiftUI Router you can power your SwiftUI app with path-based routing. By utilizing a path-based system, navigation in your app becomes ...
This package takes SwiftUI's familiar and powerful NavigationStack API and gives it superpowers, allowing you to use the same API not just ...