Swift Enums: Associated Values vs Raw Values Explained

Swift enums can do much more than just list named cases. Two of the most important enum features are raw values and associated values, and understanding the difference helps you model data correctly, write safer code, and avoid common compiler errors. In this article, you will learn what each feature does, how they differ, when to use each one, and how to apply them in realistic Swift 5+ code.

Quick answer: Use raw values when each enum case maps to one fixed underlying value such as a string or integer. Use associated values when each case needs to carry extra data that can vary at runtime, such as an ID, message, or coordinates.

Difficulty: Beginner

Helpful to know first: You will understand this better if you already know basic Swift syntax, how enums work at a simple level, and how switch statements match enum cases.

1. What Are the Options?

Swift enums support two different ways to attach meaning to cases: raw values and associated values. They solve different problems, even though beginners often confuse them.

For example, a traffic light enum is a good fit for raw values because each case can map to a stable string like "red" or "green". A server response enum is a good fit for associated values because a success case may need to store a username, token, or other returned data.

2. Side-by-Side Comparison

Feature Raw Values Associated Values
Purpose Map each case to one fixed value Store extra data for a specific enum instance
When assigned In the enum definition When creating the case value
Can vary per instance? No Yes
Common types String, Int, Double Almost any Swift type
Access pattern case.rawValue Pattern matching with switch or if case
Reverse lookup Often supported with Enum(rawValue:) Not automatic
Typical use Status codes, API strings, stored identifiers Responses, state machines, rich domain data

3. Key Differences Explained

Fixed value vs stored payload

A raw value is part of the enum case definition itself. Every time you use that case, its raw value is the same. An associated value is a payload attached to one конкрет enum instance, so it can change from one use to another.

Here is a raw value enum:

enum Direction: String {
    case north = "N"
    case south = "S"
    case east = "E"
    case west = "W"
}

Each direction always has the same string code.

Here is an associated value enum:

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

Each barcode value can carry different data depending on the case and the specific instance.

How you read them

Raw values are easy to read using the rawValue property.

let direction = Direction.north
print(direction.rawValue)

This prints the fixed raw value for the case.

Associated values are extracted with pattern matching.

let code = Barcode.qrCode("SWIFT-123")

switch code {
case .upc(let numberSystem, let manufacturer, let product, let check):
    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case .qrCode(let value):
    print("QR code: \(value)")
}

This works because associated values are not available through rawValue; they must be matched and unpacked.

When to use each

Choose raw values when your enum cases represent stable codes, labels, or identifiers. Choose associated values when cases need to carry meaningful data that belongs to a specific case instance.

4. When to Use Each

Use raw values when the case has one fixed representation

Example:

enum FileType: String {
    case pdf = "application/pdf"
    case jpeg = "image/jpeg"
    case plainText = "text/plain"
}

Each file type has one exact MIME string, so raw values are a natural fit.

Use associated values when the case needs runtime data

Example:

enum LoginResult {
    case success(String)
    case failure(String)
}

Here, the success and failure cases each carry data that changes at runtime.

5. Code Examples

Example 1: Raw values with strings

This example shows an enum whose cases map to fixed strings.

enum Season: String {
    case spring = "Spring"
    case summer = "Summer"
    case autumn = "Autumn"
    case winter = "Winter"
}

let currentSeason = Season.summer
print(currentSeason.rawValue)

The output is the raw string Summer.

Example 2: Creating from a raw value

One benefit of raw values is that Swift can often build an enum from the raw value using an initializer.

enum HTTPStatus: Int {
    case ok = 200
    case notFound = 404
    case serverError = 500
}

let status = HTTPStatus(rawValue: 404)
print(status as Any)

This returns an optional because the raw value might not match any case.

Example 3: Associated values for API results

This enum stores different kinds of data depending on the result.

enum APIResponse {
    case success(String)
    case failure(Int, String)
}

let response = APIResponse.failure(401, "Unauthorized")

switch response {
case .success(let message):
    print("Success: \(message)")
case .failure(let code, let reason):
    print("Error \(code): \(reason)")
}

The failure case carries both a code and a message, which raw values cannot express.

Example 4: Named associated values

Associated values can be clearer when you name the stored pieces of data.

enum Shape {
    case rectangle(width: Double, height: Double)
    case circle(radius: Double)
}

let shape = Shape.rectangle(width: 10.0, height: 5.0)

switch shape {
case .rectangle(let width, let height):
    print("Rectangle: \(width) x \(height)")
case .circle(let radius):
    print("Circle radius: \(radius)")
}

This makes the meaning of each value easier to understand when creating enum instances.

6. Common Mistakes

Mistake 1: Trying to read an associated value with rawValue

Beginners often assume every enum has a rawValue property. That is only true for enums declared with a raw value type.

Problem: This code treats an enum with associated values as if it had fixed raw values, so Swift reports that the member does not exist.

enum ResultState {
    case success(String)
    case failure(String)
}

let state = ResultState.success("Done")
print(state.rawValue)

Fix: Use pattern matching to extract associated values.

enum ResultState {
    case success(String)
    case failure(String)
}

let state = ResultState.success("Done")

switch state {
case .success(let message):
    print(message)
case .failure(let message):
    print(message)
}

The corrected version works because associated values must be unpacked from the enum case.

Mistake 2: Trying to assign different raw values at runtime

Raw values are fixed in the enum definition. You cannot pass a new raw value each time you create a case.

Problem: This code tries to use a raw-value enum case like a function call with changing input, but raw values are not runtime payloads.

enum UserRole: String {
    case admin
    case guest
}

let role = UserRole.admin("super-admin")

Fix: Use associated values if the case must carry changing data.

enum UserRole {
    case admin(String)
    case guest(String)
}

let role = UserRole.admin("super-admin")

The corrected version works because associated values allow the case to store data supplied at creation time.

Mistake 3: Forgetting that Enum(rawValue:) returns an optional

When you create a raw-value enum from external input, the input might not match any case.

Problem: This code assumes every integer will map to a valid case, but invalid input produces nil, which can lead to the error Value of optional type must be unwrapped.

enum Priority: Int {
    case low = 1
    case medium = 2
    case high = 3
}

let priority = Priority(rawValue: 5)
print(priority.rawValue)

Fix: Safely unwrap the optional before using it.

enum Priority: Int {
    case low = 1
    case medium = 2
    case high = 3
}

let priority = Priority(rawValue: 2)

if let priority {
    print(priority.rawValue)
}

The corrected version works because it handles the possibility that the raw value does not match a case.

7. Tradeoffs and Edge Cases

A common design clue is this: if you are asking, “What fixed code represents this case?” think raw values. If you are asking, “What data should travel with this case?” think associated values.

8. Decision Guide

9. Key Points

10. Final Summary

Swift enum raw values and associated values may look related, but they serve very different purposes. Raw values map each case to one fixed underlying value, which makes them useful for stable identifiers, saved settings, and external codes. Associated values attach runtime data to individual enum instances, which makes them ideal for responses, state, and rich domain models.

When choosing between them, focus on the job your enum needs to do. If the case always means the same fixed string or number, choose raw values. If the case needs to carry data that changes from one instance to another, choose associated values. As a next step, practice writing enums that use switch pattern matching well, since that is the key skill for working confidently with associated values.