Skip to content
  • Home
  • About us
  • Contact
  • Privacy Policy
  • Disclaimer
  • Swift Online Compiler
iOS Interview Questions and Tutorials

iOS Interview Questions and Tutorials

Enums in Swift: Brief Explanation with Code Examples

Posted on July 9, 2024 By Sid No Comments on Enums in Swift: Brief Explanation with Code Examples
Enums in Swift

Table of Contents

Toggle
  • Enums in Swift
    • Basic Enum
    • Switch Statement with Enums
    • Associated Values
      • Accessing Associated Values
      • Associated Values with Different Data Types
      • Using Associated Values in Methods
      • Nested Enums with Associated Values
    • Raw Values
      • Basic Example
      • Implicit Raw Values
      • Initializing from Raw Values
      • Raw Values with Different Types
      • Practical Usage
    • Methods in Enums
    • Enum with Protocol Conformance
    • CaseIterable protocol
      • Using CaseIterable
      • Enum with Raw Values
      • Customizing allCases
      • Practical Usage

Enums in Swift

Enums (short for enumerations) in Swift allow you to define a common type for a group of related values and work with those values in a type-safe way within your code.

Enums in Swift can have associated values, raw values, and can also conform to protocols.

I will explain the different aspects of enums with detailed code examples below.

Basic Enum

A basic enum defines a group of related values. Here’s an example of a simple enum that represents the directions of a compass:

enum CompassDirection {
    case north
    case south
    case east
    case west
}

// Usage
let direction = CompassDirection.north
Switch Statement with Enums

Enums work well with Swift’s switch statement, allowing you to match each enum case and perform different actions for each case:

switch direction {
case .north:
    print("Heading North")
case .south:
    print("Heading South")
case .east:
    print("Heading East")
case .west:
    print("Heading West")
}
Associated Values

Associated values in Swift enums allow you to store additional information along with each case of the enum.

This is particularly useful when the cases of an enum need to carry different types or amounts of data.

By using associated values, enums can be more expressive and versatile.

Basic Example

Consider an enum that represents different types of barcodes. Each barcode type can have different associated values:

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

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

In this example, the Barcode enum has two cases: upc and qrCode. The upc case has four associated integer values, while the qrCode case has one associated string value.

Accessing Associated Values

You can access the associated values of an enum case using a switch statement or optional binding:

Using Switch Statement

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

Using Optional Binding

if case let .qrCode(code) = productBarcode {
    print("QR Code: \(code)")
}
Associated Values with Different Data Types

Enums with associated values can store different types of data for each case. This can be useful for modeling complex data structures. Here’s an example of an enum that represents a response from a server:

enum ServerResponse {
    case success(String, Int)
    case error(String)
}

// Usage
let successResponse = ServerResponse.success("Data received", 200)
let errorResponse = ServerResponse.error("Not found")

switch successResponse {
case .success(let message, let statusCode):
    print("Success: \(message), Status code: \(statusCode)")
case .error(let errorMessage):
    print("Error: \(errorMessage)")
}
Using Associated Values in Methods

You can use associated values within methods to encapsulate functionality related to each case:

enum MathOperation {
    case addition(Int, Int)
    case subtraction(Int, Int)
    case multiplication(Int, Int)
    case division(Int, Int)

    func perform() -> Int {
        switch self {
        case .addition(let a, let b):
            return a + b
        case .subtraction(let a, let b):
            return a - b
        case .multiplication(let a, let b):
            return a * b
        case .division(let a, let b):
            return a / b
        }
    }
}

// Usage
let operation = MathOperation.addition(5, 3)
print("Result: \(operation.perform())")  // Output: Result: 8
Nested Enums with Associated Values

Enums can be nested and can have associated values, providing even more flexibility:

enum Device {
    case phone(model: String)
    case laptop(model: String, isTouchscreen: Bool)

    enum OperatingSystem {
        case iOS
        case macOS
        case windows
        case linux
    }

    var os: OperatingSystem {
        switch self {
        case .phone:
            return .iOS
        case .laptop(let model, _):
            return model == "MacBook" ? .macOS : .windows
        }
    }
}

// Usage
let myDevice = Device.laptop(model: "MacBook", isTouchscreen: false)
print("Operating System: \(myDevice.os)")  // Output: Operating System: macOS

Summary

Associated values in Swift enums provide a powerful way to represent a variety of related data in a type-safe manner. They allow enums to store additional information for each case, making them versatile and expressive. By using associated values, you can create more complex data structures and encapsulate related functionality within your enums, leading to cleaner and more maintainable code.

Raw Values

Raw values in Swift enums allow you to assign a default value to each case. These raw values can be of type String, Character, or any integer or floating-point number. Unlike associated values, where each case can have different types of additional data, raw values provide a common value type for all cases in the enum.

Here’s a detailed explanation of raw values with examples:

Basic Example

Here’s an example of an enum with raw values of type String:

enum Planet: String {
    case mercury = "Mercury"
    case venus = "Venus"
    case earth = "Earth"
    case mars = "Mars"
}

// Usage
let planet = Planet.earth
print("Planet: \(planet.rawValue)")  // Output: Planet: Earth

In this example, each case of the Planet enum is assigned a raw value of type String. The rawValue property can be used to access the raw value associated with each case.

Implicit Raw Values

If the raw value type is an integer or string, and you do not explicitly assign raw values, Swift will automatically assign them. For strings, each case’s name is used as its raw value. For integers, the first case is assigned the value 0 by default, and subsequent cases are assigned values incremented by 1.

String Example

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

// Usage
let direction = Direction.east
print("Direction: \(direction.rawValue)")  // Output: Direction: east

Integer Example

enum Day: Int {
    case sunday
    case monday
    case tuesday
    case wednesday
    case thursday
    case friday
    case saturday
}

// Usage

let day = Day.friday
print("Day: \(day.rawValue)")  // Output: Day: 5
Initializing from Raw Values

You can initialize an enum instance using a raw value. This initializer returns an optional enum case because the raw value might not correspond to any case in the enum.

if let possiblePlanet = Planet(rawValue: "Earth") {
    print("Planet: \(possiblePlanet)")  // Output: Planet: earth
} else {
    print("No such planet")
}

if let day = Day(rawValue: 3) {
    print("Day: \(day)")  // Output: Day: wednesday
} else {
    print("No such day")
}
Raw Values with Different Types

Raw values can be of any type that conforms to the RawRepresentable protocol, such as Int, Double, Character, etc.

Character Example

enum Alphabet: Character {
    case a = "A"
    case b = "B"
    case c = "C"
    case d = "D"
}

// Usage
let letter = Alphabet.c
print("Letter: \(letter.rawValue)")  // Output: Letter: C

Double Example

enum Coin: Double {
case penny = 0.01
case nickel = 0.05
case dime = 0.10
case quarter = 0.25
}

// Usage
let coin = Coin.quarter
print("Coin value: \(coin.rawValue)") // Output: Coin value: 0.25
Practical Usage

Raw values are useful when you need a predefined value associated with each enum case, such as representing days of the week, HTTP status codes, or mapping to string identifiers.

HTTP Status Code Example :

enum HTTPStatusCode: Int {
    case ok = 200
    case notFound = 404
    case internalServerError = 500
}

// Usage
let statusCode = HTTPStatusCode.notFound
print("Status code: \(statusCode.rawValue)")  // Output: Status code: 404

Summary

Raw values in Swift enums provide a convenient way to associate constant values with each case. They can be of various types, including strings, integers, characters, and floating-point numbers. Raw values are useful for creating enums that map to external data sources or predefined sets of values, and they support automatic value assignment for string and integer types. By using raw values, you can simplify your code and make it more readable and maintainable.

Methods in Enums

Enums can have methods associated with them to encapsulate functionality related to the enum:

enum Beverage: String {
    case coffee, tea, juice

    func description() -> String {
        switch self {
        case .coffee:
            return "Coffee is a brewed drink."
        case .tea:
            return "Tea is an aromatic beverage."
        case .juice:
            return "Juice is a drink made from fruit."
        }
    }
}

// Usage
let drink = Beverage.coffee
print(drink.description())
Enum with Protocol Conformance

Enums can conform to protocols just like other types. This is useful for adding common functionality:

protocol Describable {
    func describe() -> String
}

enum Animal: Describable {
    case cat, dog, bird

    func describe() -> String {
        switch self {
        case .cat:
            return "A small domesticated carnivorous mammal."
        case .dog:
            return "A domesticated carnivorous mammal that typically has a long snout."
        case .bird:
            return "A warm-blooded egg-laying vertebrate animal."
        }
    }
}

// Usage
let pet = Animal.dog
print(pet.describe())
CaseIterable protocol

The CaseIterable protocol in Swift allows you to access a collection of all the cases of an enum.

This can be particularly useful when you need to iterate over all possible values of an enum.

To use CaseIterable, simply declare your enum as conforming to the CaseIterable protocol.

Here’s a detailed explanation and examples:

Using CaseIterable

Basic Example

First, let’s see a simple example of an enum conforming to CaseIterable:

enum CompassDirection: CaseIterable {
    case north
    case south
    case east
    case west
}

// Usage
for direction in CompassDirection.allCases {
    print(direction)
}

In this example, CompassDirection conforms to CaseIterable, which automatically provides a static allCases property containing a collection of all the cases in the enum. The for loop then iterates over each direction and prints it.

Enum with Raw Values

CaseIterable can also be used with enums that have raw values:

enum Beverage: String, CaseIterable {
    case coffee
    case tea
    case juice
}

// Usage
for drink in Beverage.allCases {
    print(drink.rawValue)
}

In this example, Beverage is an enum with raw values of type String. The CaseIterable conformance allows you to iterate over all the cases and print their raw values.

Customizing allCases

By default, the allCases property is automatically synthesized by the compiler. However, you can customize it if you need a different behavior. Here’s how:

enum Planet: CaseIterable {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune

   static var allCases: [Planet] {
        return [.mercury, .venus, .earth, .mars, .jupiter, .saturn, .uranus, .neptune]
    }
}

In this example, although the default synthesis of allCases would suffice, you have the option to provide your own implementation if needed.

Practical Usage

Let’s consider a practical scenario where you might use CaseIterable. Suppose you have an enum representing different types of notifications in an app, and you want to display all the notification types in a list:

enum NotificationType: CaseIterable {
    case email
    case sms
    case push
}

// Usage
for notification in NotificationType.allCases {
    print("Notification type: \(notification)")
}

// Output:
// Notification type: email
// Notification type: sms
// Notification type: push

This approach ensures that any changes to the enum, such as adding or removing cases, are automatically reflected wherever allCases is used, making your code more maintainable.

Summary

The CaseIterable protocol is a convenient way to work with all the cases of an enum in Swift. It provides an allCases property that you can use to iterate over each case, making it easy to handle scenarios where you need to work with the full set of possible values of an enum. Whether for iterating over cases, generating test data, or populating UI components, CaseIterable enhances the flexibility and usability of enums in Swift.

 

Read More

Enumerations

Top iOS Interview Questions and Answers

Blog Tags:Associated Values, Enums in Swift

Post navigation

Previous Post: Higher-Order Functions in Swift: Brief Explanation with Code Examples

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Most Asked iOS Interview Questions

  • Top iOS Interview Questions and Answers

Categories

  • Associated Types(7)
  • Blog
  • Dictionary in Swift(20)
  • Initializers
  • Property Wrapper
  • Singleton in Swift
  • User Defaults(4)
  • XCode 15 Errors

Recent Comments

  1. Sid on Cycle inside MyApp; building could produce unreliable results
  2. Anominous on Cycle inside MyApp; building could produce unreliable results
  3. Aisha on @objc Attribute in Swift

Recent Posts

  • Enums in Swift: Brief Explanation with Code Examples
  • Higher-Order Functions in Swift: Brief Explanation with Code Examples
  • Mutability in Structs and Classes in Swift
  • Delegate Pattern in Swift
  • resueIdentifier in Swift

DSA in Swift

  • 2D Array in Swift: Interview Questions

Copyright © 2025 iOS Interview Questions and Tutorials.

Powered by PressBook WordPress theme