Working with Enumerations
1. Defining Enumerations
| Feature | Description | Example |
|---|---|---|
| Basic Enum | Defines a set of named constants. | |
| Raw Values | Assigns a value to each case, such as String or Int. | |
| Associated Values | Each case can hold associated values of any type. | |
| Implicit Cases | Case values are implicitly provided if not specified. | |
Example: Using Raw Values
enum Direction: String {
case left = "turnLeft"
case right = "turnRight"
}
let direction = Direction.left
print(direction.rawValue) // Output: turnLeft
Example: Using Associated Values
enum PaymentMethod {
case creditCard(String, Int)
case bankTransfer(String)
}
let payment = PaymentMethod.creditCard("1234", 1234)
switch payment {
case .creditCard(let number, let cvv):
print("Card: \(number), CVV: \(cvv)")
case .bankTransfer(let account):
print("Account: \(account)")
}
2. Using Raw Values
| Enumeration | Raw Value Type | Raw Values |
|---|---|---|
| Color | String |
"red", "green", "blue" |
| ErrorCode | Int |
100, 200, 404 |
Example: Accessing Raw Values
enum Color: String {
case red = "red"
case green = "green"
case blue = "blue"
}
let color = Color.red
print(color.rawValue) // Output: red
Example: Initializing from Raw Values
enum ErrorCode: Int {
case success = 200
case notFound = 404
case serverError = 500
}
if let code = ErrorCode(rawValue: 404) {
print("Error: \(code)") // Output: Error: notFound
}
Note: Raw values must be unique within the enumeration and are assigned at compile time.
3. Using Associated Values
Associated values allow you to attach data of any type to each case of an enumeration. This is particularly useful for representing variants of a type that carry additional information.
| Case | Associated Value Type | Description |
|---|---|---|
| success | String |
Represents a successful operation with a message. |
| failure | Error |
Represents a failed operation with an error object. |
Example: Defining an Enum with Associated Values
enum NetworkResult {
case success(String)
case failure(Error)
}
let result = NetworkResult.success("Data loaded successfully")
Example: Using Associated Values in a Switch Statement
func handleResult(_ result: NetworkResult) {
switch result {
case .success(let message):
print("Success: \(message)")
case .failure(let error):
print("Failure: \(error.localizedDescription)")
}
}
handleResult(NetworkResult.success("Loaded"))
4. Matching Enumeration Values
| Pattern | Description | Usage |
|---|---|---|
| switch | Matches enumeration values with exhaustive cases | |
| if case | Matches a specific case and extracts associated value | |
| guard case | Exits early if a case does not match | |
Example: Switch with Associated Values
enum NetworkError: Error {
case timeout(seconds: Int)
case invalidURL(String)
case serverError(Int)
}
func handleNetworkError(_ error: NetworkError) {
switch error {
case .timeout(let seconds):
print("Request timed out after \(seconds) seconds")
case .invalidURL(let url):
print("Invalid URL: \(url)")
case .serverError(let code):
print("Server error with code: \(code)")
}
}
Example: Using if case for Optional Enum
enum Result<T> {
case success(T)
case failure(String)
}
let optionalResult: Result<String> = .success("Hello")
if case .success(let value) = optionalResult {
print(value) // Prints: Hello
}
Note: The
switch statement must be exhaustive when matching all cases of an enum, or use _ to handle remaining cases.
Warning: When using
if case, ensure that the pattern matches the actual enum case to avoid runtime errors.
5. Using Recursive Enumerations
Recursive enumerations in Swift allow an enumeration to have cases that refer to the enumeration type itself. This is particularly useful for modeling hierarchical or tree-like structures.
| Case | Description | Usage Example |
|---|---|---|
| leaf | Represents a terminal node in the tree structure. | .leaf(42) |
| node | Represents a node that contains other nodes or leaves. | .node(.leaf(1), .leaf(2)) |
Example: Using Recursive Enum
let tree = Tree.node(.leaf(1), .leaf(2))
print(tree) // Output: node(leaf(1), leaf(2))
Note: Recursive enums must be declared with a generic type parameter to allow self-referencing.
6. Iterating Enumeration Cases
| Case | Description | Usage |
|---|---|---|
| allCases | Provides a collection of all cases in an enumeration. | |
| CaseIterable | Protocol that allows enumeration to be iterated over all its cases. | |
7. Adding Computed Properties
| Property | Type | Description |
|---|---|---|
| rawValue | String |
Computed property that returns the raw value of the enum case. |
| isAvailable | Bool |
Computed property indicating if the enum case is available in current context. |
Example: Using Computed Properties in an Enum
enum NetworkStatus {
case online
case offline
case connecting
var rawValue: String {
switch self {
case .online: return "Online"
case .offline: return "Offline"
case .connecting: return "Connecting"
}
}
var isAvailable: Bool {
switch self {
case .online, .connecting: return true
case .offline: return false
}
}
}
let status = NetworkStatus.online
print(status.rawValue) // "Online"
print(status.isAvailable) // true
8. Adding Methods to Enumerations
In Swift, you can add methods to enumerations using the static keyword for type-level methods or self for instance methods. These methods can access the enumeration's cases and associated values.
| Method Type | Description | Example |
|---|---|---|
| Instance Method | Operates on a specific instance of the enum. | |
| Static Method | Operates on the enum type itself, not an instance. | |
Example: Using Associated Values with Methods
enum Shape {
case circle(radius: Double)
case rectangle(width: Double, height: Double)
func area() -> Double {
switch self {
case .circle(let radius):
return Double.pi * radius * radius
case .rectangle(let width, let height):
return width * height
}
}
}
let circle = Shape.circle(radius: 5.0)
let rectangle = Shape.rectangle(width: 4.0, height: 6.0)
print(circle.area()) // Output: 78.53981633974483
print(rectangle.area()) // Output: 24.0
9. Using Enum Initializers
| Initializer | Description | Example |
|---|---|---|
| init(rawValue: String) | Initializes an enum with a raw value of type String | |
| init?(rawValue: RawValue) | Initializes an enum with a raw value, returning an optional | |
| init?(rawValue: Int) | Initializes an enum with a raw value of type Int | |
Note: Raw values must be unique within the enum.
10. Implementing Custom String Convertible
| Protocol | Description | Usage |
|---|---|---|
| CustomStringConvertible | Defines a custom string representation for a type. | Used to provide a human-readable description of an instance. |