Enumerations (or enums for short) in Swift define a common type for a group of related values. According to the Swift documentation, enums enable you to work with those values in a type-safe way within your code. Enums come in particularly handy when you have a lot of different options you want to encode.
Using enum
in Swift is similar to writing code that returns a boolean — e.g., true
or false
— when a condition is met. In the case of enums, however, you can have more than two possible values.
Think of an enum like a thermostat. There is a range of values that could possibly match the outcome — e.g., low, medium, high, extreme. Depending on the case that is matched, we’ll want to run some specified code.
An enum is a special type of variable that is specifically used with switch and conditionals. Swift enumeration cases don’t have unique default integer values (like an array), unlike languages such as TypeScript and Objective C where the first element has a value of 0
, the second a value of 1
, and so on.
In this tutorial, we’ll cover all the basics of Swift enums, including:
CaseIterable
in enumeration casesTo define an enum in Swift, use the keyword enum
followed by the name of the enum. The name of an enum in Swift should follow the PascalCase naming convention in which the first letter of each word in a compound word is capitalized.
// starts with the keyword 'enum'and follows the PascalCase naming convention enum EnumerationNmae { // our enum values (case) goes in here }
Here is a closer look at how to declare values in an enum:
enum Direction { case up case down case left case right }
The values declared in an enum — up
, down
, left
and right
— are referred to as enumeration case. We use the case keyword to introduce a new enumeration case.
Enums are particularly useful inside switch
statements, as opposed to an if-else
statement. That’s because in a switch statement Swift knows all the values the enum holds, so it will ensure you cover all the cases in your enum or add a default case.
CaseIterable
in enumeration casesCaseIterable
is a type that provides a collection of all the values of an enumeration. It’s used to iterate over all the cases in an enum.
To do this, add CaseIterable
after the name of the enum. With that in place, Swift will give us access to a collection of all the cases through a property on the enumeration type called allCases
.
enum CarBrand: String, CaseIterable { case Mercedes = "Known for luxury and iconic design. Definitely my fav!" case Toyota = "Known for high-quality, high-value cars" case Volkswagen = "This is the people's car" case Ford = "Known for crisp handling, absorbent ride, and solid feel" case Honda = "Known for their well-built, reliable cars" }
To access the collection of all the cases in our CarBrand
enum, we can do this:
print(CarBrand.allCases.count) // expected output: 5
In the example above, we wrote CarBrand.allCases
to access a collection that contains all of the cases of the CarBrand
enumeration. The count
method gives the number of elements in our collection.
We can go further by using a for
loop over all the cases in our enum.
Let’s print put the raw value in our enumeration cases using the allCases
method:
// create an enum with a CaseIterable type enum CarBrand: String, CaseIterable { case Mercedes = "Known for luxury and iconic design. Definitely my fav!" case Toyota = "Known for high-quality, high-value cars" case Volkswagen = "This is the people's car" case Ford = "Known for crisp handling, absorbent ride, and solid feel" case Honda = "Known for their well-built, reliable cars" } // we are looping through our enum and accessing all its raw values for brand in CarBrand.allCases { print(brand.rawValue) } // expected output: // Known for luxury and iconic design. Definitely my fav! // Known for high-quality, high-value cars // This is the people's car // Known for crisp handling, absorbent ride, and solid feel // Known for their well-built, reliable cars
In our enum, we can declare a raw value type. This essentially means attaching a value to the enum case.
To better understand raw values in enums, let’s create an enum of type string (it can be any type) to hold different brands of cars along with attributes for which each brand is known (these will be the raw values):
// Enum with raw values enum CarBrand: String { case Mercedes = "Known for luxury and iconic design. Definitely my fav!" case Toyota = "Known for high-quality, high-value cars" case Volkswagen = "This is the people's car" case Ford = "Known for crisp handling, absorbent ride, and solid feel" case Honda = "Known for their well-built, reliable cars" }
To set a value to your enum, you need to assign a data type to it. In our case above, we are using a type of String
.
Each raw value for our enum case must be a unique string, character, or value of any integer or floating-point type. This means the value for the two case statements cannot be the same. See the code below:
enum CarBrand: String { case Toyota = "High value cars." case Volkswagen = "High value cars." }
The code above throws an error of “Raw value for enum case is not unique
” because both case values are exactly the same.
Now that we’ve created our enum with each enumeration case having a raw value, let’s create a function that will return the rawValue
of the various car brands. The raw values here represent the attributes each brand is known for:
func carKnownFor(brand: CarBrand) -> String { return brand.rawValue } carKnownFor(brand: .Ford) carKnownFor(brand: .Mercedes) // expected output: // "Known for luxury and iconic design. Definitely my fav!" // "Known for crisp handling, absorbent ride, and solid feel"
One of the best features of enumerations in Swift is that you can have values that you define attach to enums in each case
. This enables you to attach additional information to your enums so they can represent more meaningful data.
For example, let’s say we have an enum that defines the prices of Mercedes cars. Based on the price, we want to determine whether a user can afford the model of car or not. We can associate a price with the brand of car in our enum
as we have in the example below:
// enum with associated values enum MercedesModelPrice { case MayBach(price: Int) case AMG_GT(price: Int) case Metris(price: Int) case SprinterWagon(price: Int) case GClass }
// enum without associated values enum MercedesModelPrice { case MayBach case AMG_GT case Metris case SprinterWagon case GClass }
Now, let’s create a function to check whether a user can afford a Mercedes:
func getMercedesPrice(for mercedesModel: MercedesModelPrice) { switch mercedesModel { case .MayBach(price: let price) where price >= 100_000: print("You just bought yourself a new car") case .Metris(price: let price) where price >= 86_000: print("You just bought yourself a new car") case .AMG_GT(price: let price) where price >= 74_000: print("You just bought yourself a new car") case .SprinterWagon(price: let price) where price >= 45_000: print("You just bought yourself a new car") case .GClass, .SprinterWagon, .Metris, .AMG_GT, .MayBach: print("Insufficient funds. You cant' afford this car at the moment") } } // Calling our function getMercedesPrice(for: .SprinterWagon(price: 200_000)) // expected output: You just bought yourself a new car
Notice how we’re using the where
keyword to filter the case
for a specific price.
It’s worth noting that the order of the case
statement matters. Putting the last case
statement (case .GClass, .SprinterWagon, .Metris, .AMG_GT, .MayBach:
) first means we’ll always get the result attached to this case as a match.
Apart from defining enumeration cases in our enum, we can also define methods in our enum
, like this:
enum Weekday { case Monday case Tuesday case Wednesday case Thursday case Friday case Saturday case Sunday func dayType() -> String { switch self { case .Sunday, .Saturday: return "Weekend" default: return "Weekday" } } } Weekday.Monday.dayType() // this will return "Weekday" Weekday.Sunday.dayType() // this will return "Weekend"
In the code snippet above, we’re using the switch statement within the dayType
method to return Weekend
or Weekday
as the output depending on the day of the week.
You can also use computed properties in enums in place of functions.
Let’s replace the dayType
function we have in our code above with a computed property:
enum Weekday { case Monday case Tuesday case Wednesday case Thursday case Friday case Saturday case Sunday var dayType: String { self == .Saturday || self == .Sunday ? "Weekend" : "Weekday" } } Weekday.Monday.dayType // this will return "Weekday" Weekday.Sunday.dayType // this will return "Weekend" >
Swift enums can be a powerful way to simplify your code. In this tutorial, we covered the syntax of enums
and how to define them, how to create enumeration cases, and how to use them in switch
statements. We also defined CaseIterable
as a type that provides a collection of all the values of the enumeration. We covered enum values (both raw and associated values) and how to use them in our codebase. Finally, we demonstrated how to use computed properties in Swift enums in place of functions.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.