Enums with Associated Values
Prerequisites: Enums
Enum cases can carry extra data, called associated values, and each case can carry different data. This makes enums one of Swift's most powerful tools for modeling states.
Example
enum PaymentMethod {
case cash
case card(last4: String)
case voucher(code: String, amount: Double)
}
func describe(_ method: PaymentMethod) -> String {
switch method {
case .cash:
"Cash"
case .card(let last4):
"Card ending in \(last4)"
case .voucher(let code, let amount) where amount >= 50:
"Large voucher \(code)"
case .voucher(let code, _):
"Voucher \(code)"
}
}
print(describe(.cash))
print(describe(.card(last4: "4242")))
print(describe(.voucher(code: "SPRING", amount: 75)))
print(describe(.voucher(code: "SMALL", amount: 10)))
Expected output
Cash
Card ending in 4242
Large voucher SPRING
Voucher SMALL
case .card(let last4)matches the case and pulls out its value._ignores a value you don't need.whereadds a condition to a pattern.
Modeling state
Associated values make impossible states impossible. Compare a loading
screen modeled with separate optionals — which could accidentally have
both data and error set — with an enum:
enum LoadState {
case idle
case loading
case loaded([String])
case failed(message: String)
}
let state = LoadState.loaded(["Ada", "Linus"])
if case .loaded(let names) = state {
print("Loaded \(names.count) names")
}
Loaded 2 names
if case checks for a single case without a full switch.
Swift's own Optional is an enum with two cases, .some(value) and
.none — which is why nil fits so naturally into the language. The
standard Result<Success, Failure> type is another: .success(value)
or .failure(error).
Practice
Define enum Shape with circle(radius: Double) and
rectangle(width: Double, height: Double), and a function returning
each shape's area. Print the areas of a circle of radius 1 (rounded to
two decimal places) and a 2 by 3 rectangle.
Show solution
enum Shape {
case circle(radius: Double)
case rectangle(width: Double, height: Double)
}
func area(of shape: Shape) -> Double {
switch shape {
case .circle(let r): Double.pi * r * r
case .rectangle(let w, let h): w * h
}
}
let circle = area(of: .circle(radius: 1))
print((circle * 100).rounded() / 100)
print(area(of: .rectangle(width: 2, height: 3)))
3.14
6.0