Swift Enums

Type-safe way to work with groups of related values

🎯 What are Swift Enums?

Enumerations define a common type for a group of related values. Swift enums are powerful, supporting associated values, methods, and computed properties. They provide type safety and make code more readable and maintainable.


// Basic enum definition
enum Direction {
    case north
    case south
    case east
    case west
}

let currentDirection = Direction.north

switch currentDirection {
case .north:
    print("Going north!")
case .south:
    print("Going south!")
case .east:
    print("Going east!")
case .west:
    print("Going west!")
}
// Output: Going north!
                                    

Key Enum Features

🏷️

Case Values

Define related constant values

enum Planet {
    case mercury, venus, earth, mars
    case jupiter, saturn, uranus, neptune
}
📦

Associated Values

Store additional data with enum cases

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}
🔢

Raw Values

Assign default values to cases

enum StatusCode: Int {
    case ok = 200
    case notFound = 404
    case serverError = 500
}
⚙️

Methods & Properties

Add functionality to enums

enum Color {
    case red, green, blue
    
    func description() -> String {
        return "Color: \(self)"
    }
}

🔹 Basic Enum Usage

Here's how to define and use a simple enum:

enum WeatherCondition {
    case sunny
    case cloudy
    case rainy
    case snowy
    case stormy
}

func getWeatherAdvice(for weather: WeatherCondition) -> String {
    switch weather {
    case .sunny:
        return "Great day for outdoor activities!"
    case .cloudy:
        return "Perfect for a walk in the park."
    case .rainy:
        return "Don't forget your umbrella!"
    case .snowy:
        return "Time to build a snowman!"
    case .stormy:
        return "Better stay indoors."
    }
}

let today = WeatherCondition.sunny
let tomorrow = WeatherCondition.rainy

print(getWeatherAdvice(for: today))
print(getWeatherAdvice(for: tomorrow))

Output:

Great day for outdoor activities!

Don't forget your umbrella!

🔹 Enums with Raw Values

Assign raw values to enum cases for easy conversion:

enum Grade: String {
    case excellent = "A"
    case good = "B"
    case average = "C"
    case poor = "D"
    case fail = "F"
    
    var description: String {
        switch self {
        case .excellent:
            return "Outstanding work!"
        case .good:
            return "Good job!"
        case .average:
            return "Satisfactory"
        case .poor:
            return "Needs improvement"
        case .fail:
            return "Must retake"
        }
    }
}

let studentGrade = Grade.good
print("Grade: \(studentGrade.rawValue)")
print("Feedback: \(studentGrade.description)")

// Create enum from raw value
if let gradeFromString = Grade(rawValue: "A") {
    print("Created grade: \(gradeFromString.description)")
}

Output:

Grade: B

Feedback: Good job!

Created grade: Outstanding work!

🔹 Associated Values

Store additional information with enum cases:

enum NetworkResponse {
    case success(data: String)
    case failure(error: String, code: Int)
    case loading
}

func handleResponse(_ response: NetworkResponse) {
    switch response {
    case .success(let data):
        print("Success! Received data: \(data)")
    case .failure(let error, let code):
        print("Error \(code): \(error)")
    case .loading:
        print("Loading...")
    }
}

let responses: [NetworkResponse] = [
    .loading,
    .success(data: "User profile loaded"),
    .failure(error: "Network timeout", code: 408)
]

for response in responses {
    handleResponse(response)
}

Output:

Loading...

Success! Received data: User profile loaded

Error 408: Network timeout

🔹 Enum Methods and Computed Properties

Add functionality directly to your enums:

enum Size: String, CaseIterable {
    case small = "S"
    case medium = "M"
    case large = "L"
    case extraLarge = "XL"
    
    var price: Double {
        switch self {
        case .small:
            return 10.0
        case .medium:
            return 12.0
        case .large:
            return 15.0
        case .extraLarge:
            return 18.0
        }
    }
    
    func isLargerThan(_ other: Size) -> Bool {
        return self.price > other.price
    }
    
    static func allSizes() -> String {
        return Size.allCases.map { $0.rawValue }.joined(separator: ", ")
    }
}

let mySize = Size.large
let otherSize = Size.medium

print("Size \(mySize.rawValue) costs $\(mySize.price)")
print("Is \(mySize.rawValue) larger than \(otherSize.rawValue)? \(mySize.isLargerThan(otherSize))")
print("Available sizes: \(Size.allSizes())")

Output:

Size L costs $15.0

Is L larger than M? true

Available sizes: S, M, L, XL

🔹 Best Practices

Follow these guidelines when working with enums:

✅ Good Practices:

  • Use descriptive names: Make enum cases self-explanatory
  • Group related values: Only put related constants in the same enum
  • Leverage switch statements: Handle all cases for type safety
  • Add methods when useful: Enums can have behavior, not just data
  • Use CaseIterable: When you need to iterate over all cases

💡 When to Use Enums:

  • Representing a fixed set of options (directions, states, types)
  • Modeling different types of data (success/failure, different shapes)
  • Creating type-safe constants instead of strings or integers
  • Implementing state machines or finite state systems

🧠 Test Your Knowledge

What keyword is used to define an enumeration in Swift?