Skip to content
AgileLogics
5 min read

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.
  • where adds 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