Skip to main content

Swift Enumerations Basics

Introduction

Enumerations (also known as enums) are a powerful feature in Swift that define a common type for a group of related values. They allow you to work with those values in a type-safe way within your code. Unlike enums in some other programming languages, Swift enumerations are first-class types that adopt many features traditionally supported only by classes.

In this tutorial, you'll learn how to:

  • Define and use basic enumerations
  • Work with enum case values
  • Use switch statements with enums
  • Understand raw values and associated values
  • Apply enumerations in practical scenarios

What is an Enumeration?

An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code. Enumerations in Swift are much more flexible than their counterparts in C and many other languages.

Basic Syntax

Here's how to define a simple enumeration in Swift:

swift
enum Direction {
case north
case south
case east
case west
}

You can also write the cases on a single line, separated by commas:

swift
enum Direction {
case north, south, east, west
}

Each enumeration definition creates a brand new type. Like other types in Swift, their names should start with a capital letter.

Using Enumerations

Once you define an enumeration, you can create instances of it:

swift
var currentDirection = Direction.north

When the type of the variable is already known, you can use a shorter dot syntax:

swift
currentDirection = .east

Example: Direction Guidance

swift
enum Direction {
case north, south, east, west
}

func provideDirections(heading: Direction) {
switch heading {
case .north:
print("Head north toward the mountain")
case .south:
print("Head south toward the lake")
case .east:
print("Head east toward the river")
case .west:
print("Head west toward the forest")
}
}

let myDirection = Direction.south
provideDirections(heading: myDirection)
// Output: Head south toward the lake

Matching Enum Values with Switch Statement

Enumerations work especially well with Swift's switch statements:

swift
let direction = Direction.west

switch direction {
case .north:
print("Heading north")
case .south:
print("Heading south")
case .east:
print("Heading east")
case .west:
print("Heading west")
}
// Output: Heading west

One important feature of Swift's switch statement is that it must be exhaustive when used with enumerations. This means you must cover all possible cases, or include a default case.

Enum with Raw Values

You can assign raw values to enumeration cases, which can be strings, characters, or any integer or floating-point type:

swift
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}

In this example, venus has an implicit raw value of 2, earth is 3, and so on.

You can access the raw value using the rawValue property:

swift
let earthOrder = Planet.earth.rawValue
print("Earth is planet number \(earthOrder) from the sun")
// Output: Earth is planet number 3 from the sun

You can also initialize an enum instance from a raw value:

swift
if let possiblePlanet = Planet(rawValue: 4) {
print("The fourth planet is \(possiblePlanet)")
}
// Output: The fourth planet is mars

Example: HTTP Status Codes

swift
enum HTTPStatus: Int {
case ok = 200
case created = 201
case accepted = 202
case noContent = 204
case badRequest = 400
case unauthorized = 401
case forbidden = 403
case notFound = 404
case serverError = 500
}

func handleResponse(statusCode: Int) {
guard let status = HTTPStatus(rawValue: statusCode) else {
print("Unknown status code: \(statusCode)")
return
}

switch status {
case .ok, .created, .accepted, .noContent:
print("Success with code \(status.rawValue)")
case .badRequest, .unauthorized, .forbidden, .notFound:
print("Client error with code \(status.rawValue)")
case .serverError:
print("Server error with code \(status.rawValue)")
}
}

handleResponse(statusCode: 200)
// Output: Success with code 200

handleResponse(statusCode: 404)
// Output: Client error with code 404

handleResponse(statusCode: 418)
// Output: Unknown status code: 418

String Raw Values

String raw values are particularly useful for enums:

swift
enum Beverage: String {
case coffee = "Coffee"
case tea = "Tea"
case juice = "Juice"
case water = "Water"
}

print("I'd like a cup of \(Beverage.tea.rawValue), please.")
// Output: I'd like a cup of Tea, please.

If you don't specify raw values for string-based enums, Swift will use the case name as the raw value:

swift
enum Direction: String {
case north, south, east, west
}

print(Direction.south.rawValue) // Output: south

Associated Values

Swift enumerations can also store associated values of any type. This allows you to attach additional information to enum cases:

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

With this, you can create barcodes of either type:

swift
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

You can extract the associated values using a switch statement:

swift
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case .qrCode(let productCode):
print("QR code: \(productCode)")
}
// Output: QR code: ABCDEFGHIJKLMNOP

Example: Result Type

Associated values are commonly used in Swift's error handling pattern:

swift
enum NetworkResult {
case success(Data)
case failure(Error)
}

func fetchData(completion: (NetworkResult) -> Void) {
// Simulate network request
if Bool.random() {
let data = "Response data".data(using: .utf8)!
completion(.success(data))
} else {
struct NetworkError: Error {
let message: String
}
completion(.failure(NetworkError(message: "Failed to fetch data")))
}
}

fetchData { result in
switch result {
case .success(let data):
if let string = String(data: data, encoding: .utf8) {
print("Received: \(string)")
}
case .failure(let error):
print("Error: \(error)")
}
}
// Output will be either:
// Received: Response data
// OR
// Error: NetworkError(message: "Failed to fetch data")

Practical Applications

Example 1: App Navigation

swift
enum NavigationDestination {
case home
case profile(userId: String)
case settings
case article(id: Int)
}

func navigate(to destination: NavigationDestination) {
switch destination {
case .home:
print("Navigating to Home screen")
case .profile(let userId):
print("Navigating to Profile for user \(userId)")
case .settings:
print("Navigating to Settings")
case .article(let id):
print("Navigating to Article #\(id)")
}
}

navigate(to: .home)
// Output: Navigating to Home screen

navigate(to: .profile(userId: "user123"))
// Output: Navigating to Profile for user user123

navigate(to: .article(id: 42))
// Output: Navigating to Article #42

Example 2: Pricing Strategy

swift
enum Pricing {
case fixed(Double)
case variable(base: Double, perUnit: Double)
case free

func calculate(units: Int = 1) -> Double {
switch self {
case .free:
return 0
case .fixed(let price):
return price
case .variable(let base, let perUnit):
return base + (perUnit * Double(units))
}
}
}

let subscriptionPlan = Pricing.fixed(9.99)
print("Monthly subscription: $\(subscriptionPlan.calculate())")
// Output: Monthly subscription: $9.99

let electricityBill = Pricing.variable(base: 10.0, perUnit: 0.12)
print("Electricity bill for 100 kWh: $\(electricityBill.calculate(units: 100))")
// Output: Electricity bill for 100 kWh: $22.0

let freeTrial = Pricing.free
print("Free trial cost: $\(freeTrial.calculate())")
// Output: Free trial cost: $0.0

Summary

Swift enumerations are powerful, flexible, and type-safe. They allow you to:

  • Define a group of related values as a type
  • Work with those values in a type-safe way
  • Associate raw values to enum cases for easy conversion
  • Attach additional information using associated values
  • Use pattern matching to extract associated values
  • Create enums with methods and properties (covered in more advanced tutorials)

Enumerations are an essential tool for Swift developers, helping to write more expressive, safer code that's easier to understand and maintain.

Exercises

  1. Create an enum called Day representing days of the week with appropriate raw values.
  2. Create an enum called Measurement with cases for different units (e.g., centimeters, inches) that can store a value.
  3. Implement an enum for representing results of a login operation with appropriate associated values for success and different types of failure.
  4. Create an enum for different payment methods (cash, credit card, digital wallet) with appropriate associated values.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)