Enumerations in Swift
Enumerations (enums) define a group of related values and let you work with those values in a type-safe way. Unlike enums in many other languages, Swift enums are full-fledged types โ they can have methods, computed properties, and conform to protocols.
enum Direction {
case north
case south
case east
case west
}
let heading = Direction.north
print(heading) // north
Try it Yourself ->
Raw Values
Enums can have raw values โ pre-populated values of a specific type like String, Int, or Double. Raw values are useful when you need to initialize an enum from a value or convert an enum back to its raw representation.
enum Planet: Int {
case mercury = 1
case venus = 2
case earth = 3
case mars = 4
}
let earthNumber = Planet.earth.rawValue
print(earthNumber) // 3
// Initialize from raw value
if let planet = Planet(rawValue: 2) {
print(planet) // venus
}
enum ASCIIControlCharacter: Character {
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}
Try it Yourself ->
Associated Values
This is where Swift enums really shine. Associated values let you attach additional data to each case. Each case can have different associated values of different types, making enums incredibly flexible.
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
let productBarcode = Barcode.upc(8, 85909, 51226, 3)
let anotherBarcode = Barcode.qrCode("ABCDEFGH")
switch productBarcode {
case .upc(let manufacturer, let product, let check, let _):
print("UPC: \(manufacturer)-\(product)-\(check)")
case .qrCode(let code):
print("QR: \(code)")
}
// UPC: 8-85909-51226-3
Try it Yourself ->
Switching on Enums
The switch statement is the natural way to work with enums. Swift ensures that your switch is exhaustive โ you must handle every possible case. This prevents you from forgetting to handle a new case when you add one later.
enum TrafficLight {
case red, yellow, green
}
let light = TrafficLight.green
switch light {
case .red:
print("Stop")
case .yellow:
print("Caution")
case .green:
print("Go")
}
// Go
Try it Yourself ->
Enum Methods
Enums can have methods and computed properties just like structs and classes. This lets you encapsulate behavior related to the enum's cases right inside the enum itself.
enum ServerResponse {
case result(String, String)
case failure(String)
func message() -> String {
switch self {
case .result(let success, let message):
return "\(success): \(message)"
case .failure(let error):
return "Failure: \(error)"
}
}
}
let response = ServerResponse.result("200", "OK")
print(response.message()) // 200: OK
Try it Yourself ->
CaseIterable Protocol
By conforming to CaseIterable, your enum automatically gets an allCases property that contains all of its cases. This is incredibly useful for iterating over all possible values without maintaining a separate array.
enum Season: CaseIterable {
case spring, summer, autumn, winter
}
for season in Season.allCases {
print(season)
}
// spring
// summer
// autumn
// winter
print("There are \(Season.allCases.count) seasons")
// There are 4 seasons
Try it Yourself ->