Skip to main content

Swift Raw Values

Introduction

In Swift, enumerations are first-class types that can define common types of related values together. While basic enumerations assign named values, Swift provides additional functionality through raw values - underlying values of specific types assigned to each enumeration case.

Raw values allow you to associate fixed values of a specific type (like Int, String, Character, or Double) to enum cases, making enums more powerful and versatile. This feature is particularly useful when working with data from external sources or when an enum needs to represent specific underlying values.

Understanding Raw Values

What Are Raw Values?

Raw values are underlying values of a specific type that you assign to enumeration cases. Think of them as pre-populated values that remain constant for a particular case of an enum.

Key Characteristics

  • Each raw value must be unique within the enum
  • Raw values are determined at compile-time (not runtime)
  • All cases must have raw values of the same type
  • Common raw value types include Int, String, Character, and Double

Declaring Enums with Raw Values

To declare an enum with raw values, specify the raw value type after the enum name:

swift
enum Direction: String {
case north = "NORTH"
case south = "SOUTH"
case east = "EAST"
case west = "WEST"
}

In this example, each case in the Direction enum has a String raw value.

Automatic Raw Value Assignment

Swift can automatically assign raw values in certain cases:

Integer Raw Values

When using Int as the raw value type, Swift automatically assigns values starting from 0:

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

// Raw values are automatically assigned as:
// mercury = 0, venus = 1, earth = 2, mars = 3, etc.

print(Planet.earth.rawValue) // Output: 2

You can also specify a starting value, and Swift will automatically increment for the remaining cases:

swift
enum BitwiseOperation: Int {
case and = 0
case or = 1
case xor = 2
case leftShift = 3
case rightShift = 4
}

// Raw values are explicitly assigned

String Raw Values

When using String as the raw value type, Swift uses the case name as the default raw value:

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

print(CompassPoint.north.rawValue) // Output: "north"

Of course, you can explicitly assign string values when needed:

swift
enum HTTPMethod: String {
case get = "GET"
case post = "POST"
case put = "PUT"
case delete = "DELETE"
}

print(HTTPMethod.post.rawValue) // Output: "POST"

Accessing Raw Values

You can access an enum case's raw value using the rawValue property:

swift
let earthPosition = Planet.earth.rawValue
print("Earth is the \(earthPosition + 1)st planet from the sun.")
// Output: Earth is the 3rd planet from the sun.

let requestMethod = HTTPMethod.get.rawValue
print("Making a \(requestMethod) request")
// Output: Making a GET request

Initializing from Raw Values

One of the most powerful features of raw values is the ability to create an enum instance from a raw value using an initializer:

swift
// Initialize an enum from a raw value
if let planet = Planet(rawValue: 2) {
print("The planet is \(planet)") // Output: The planet is earth
} else {
print("No planet found with that position")
}

Since not all raw values may correspond to an enum case, this initializer returns an optional enum instance:

swift
let possiblePlanet = Planet(rawValue: 9)  // Returns nil (no planet at position 9)

if let planet = possiblePlanet {
print("Found planet: \(planet)")
} else {
print("No valid planet at this position") // This will be printed
}

Practical Examples

Example 1: Weekday Representation

swift
enum Weekday: Int {
case sunday = 1, monday, tuesday, wednesday, thursday, friday, saturday

func isWeekend() -> Bool {
return self == .saturday || self == .sunday
}
}

// Using raw values to get a specific day
let dayNumber = 3
if let day = Weekday(rawValue: dayNumber) {
print("Day \(dayNumber) is \(day)")

if day.isWeekend() {
print("It's the weekend!")
} else {
print("It's a weekday.")
}
} else {
print("Invalid day number")
}

// Output:
// Day 3 is tuesday
// It's a weekday.

Example 2: API Response 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

var isSuccess: Bool {
return rawValue >= 200 && rawValue < 300
}

var message: String {
switch self {
case .ok: return "Request was successful"
case .created: return "Resource was created"
case .badRequest: return "Bad request"
case .unauthorized: return "Authentication required"
case .notFound: return "Resource not found"
case .serverError: return "Server error occurred"
default: return "Status code: \(rawValue)"
}
}
}

// Using raw values in API responses
func handleAPIResponse(statusCode: Int) {
if let status = HTTPStatus(rawValue: statusCode) {
print("Status: \(status)")
print("Message: \(status.message)")

if status.isSuccess {
print("Operation successful!")
} else {
print("Error encountered.")
}
} else {
print("Unknown status code: \(statusCode)")
}
}

handleAPIResponse(statusCode: 200)
// Output:
// Status: ok
// Message: Request was successful
// Operation successful!

handleAPIResponse(statusCode: 404)
// Output:
// Status: notFound
// Message: Resource not found
// Error encountered.

Example 3: Configuration Options with String Raw Values

swift
enum AppTheme: String {
case light = "light_theme"
case dark = "dark_theme"
case system = "system_default"

var displayName: String {
switch self {
case .light: return "Light Mode"
case .dark: return "Dark Mode"
case .system: return "System Default"
}
}
}

// Using raw values to load settings from user preferences
func loadThemePreference(storedValue: String) -> AppTheme {
// Try to create an AppTheme from the stored string value
if let theme = AppTheme(rawValue: storedValue) {
return theme
}
// Default to system theme if the stored value doesn't match any case
return .system
}

let userThemeSetting = "dark_theme"
let appTheme = loadThemePreference(storedValue: userThemeSetting)
print("Applying theme: \(appTheme.displayName)")
// Output: Applying theme: Dark Mode

// Using raw values to save settings
func saveThemePreference(_ theme: AppTheme) {
// In a real app, you would save this to UserDefaults or another storage
print("Saving theme preference: \(theme.rawValue)")
}

saveThemePreference(.light)
// Output: Saving theme preference: light_theme

When to Use Raw Values

Raw values are particularly useful in the following scenarios:

  1. Interfacing with external data: When dealing with API responses, file formats, or database values
  2. Representing specific numbers or codes: Like status codes, error codes, or specific numeric values
  3. Storing configuration values: When an enum case needs to map to a specific string or value
  4. Serialization and deserialization: Converting between enum cases and their string/numeric representations

Raw Values vs. Associated Values

It's important to understand the difference between raw values and associated values in Swift enums:

  • Raw values are predefined, fixed values assigned at compile time. All cases have the same type of raw value.
  • Associated values can vary each time you use the enum case and are set when you create an instance. Different cases can have different types of associated values.

An enum can have either raw values or associated values, but not both.

Summary

Raw values provide a powerful way to associate fixed, underlying values to enumeration cases in Swift:

  • Raw values must be of the same type for all cases in an enum
  • Common raw value types include Int, String, Character, and Double
  • Swift can automatically assign raw values (integers starting from 0, or strings matching case names)
  • You can access raw values using the rawValue property
  • You can initialize enum cases from raw values using Enum(rawValue:), which returns an optional
  • Raw values are useful when working with external data, serialization, or when enum cases need specific underlying values

Exercises

  1. Create an enum for representing playing card suits (hearts, diamonds, clubs, spades) with a String raw value for each.

  2. Define an enum for HTTP methods (get, post, put, delete) with appropriate string raw values, and add a property that returns whether the method is "safe" (doesn't modify data).

  3. Create an enum for representing error types in your application with integer raw values. Include at least 5 different error types and add a computed property that returns an appropriate error message for each type.

  4. Create a function that takes a raw value as input and tries to convert it to a month enum case. Return the number of days in that month (accounting for February having 28 or 29 days in leap years).

Additional Resources



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