What are enums in Swift?

Published on: May 8, 2024

Swift comes with types of objects that we can use to write type declarations. They all have their own distinct features, upsides, and downsides. In this post I’d like to zoom in on the enum type so you can get a sense of what enums are, and when they can be useful.

In this post we’ll cover the following topics:

  • Understanding the basics of enums
  • Knowing when an enum should be used
  • Avoiding enum overuse

Let's jump right in!

Understanding the basics of enums

In Swift, enums are values types that are declared using the enum keyword. Every possible value of the enum is called a "case". Enums can either be used as a list of cases that models specific (mutually exclusive) values or constants. For example, we could represent a list of operating systems for SwiftUI apps as follows:

enum OperatingSystem {
  case iOS, iPadOS, macOS, visionOS, tvOS, watchOS

If we were to pass an operating system to a function or assign it to a variable, that would look a little like this:

// assigning a variable
var os: OperatingSystem = .macOS

// or passing to a function
let binary = buildAppBinaryFor(.watchOS)

Since enums are first class citizens in Swift, they can conform to protocols, define functions, and even have computed properties. Note that you can’t add stored properties to an enum like you can to a struct.

Enums are incredibly useful when we need to represent a finite set of predefined states. With a enum, it’s impossible to create or use state that are not correct which can be incredibly useful. Imagine that you’d have to manually type out an animation type as a string in SwiftUI instead of passing .easeInOut and knowing that if your code compiles you passed a correct animation type. If you had to pass the string "easeInOut" the compiler wouldn’t be able to type check that you passed a valid value and you could be bitten by typos such as "aeseInOut" which isn’t ideal.

Even though you can’t leverage stored properties when using enums, you can associate values with enums and you can give them raw values.

An enum with raw values looks like this:

enum OperatingSystem: String {
  case iOS = "iOS"
  case iPadOS = "iPadOS"
  case macOS = "macOS"
  // etc...

In this case, my raw enum values match the enum case names directly. This means that instead of adding every possible value after the case name, I can specify that my enum uses a raw String value without modifying my cases:

enum OperatingSystem: String {
  case iOS, iPadOS, macOS, visionOS, tvOS, watchOS

Defining enums with raw values is incredibly useful when you want to create your enum values from external resources like when you’re decoding JSON. Having raw values allows you to create enum instances like this:

let os: OperatingSystem? = OperatingSystem(rawValue: "iOS")

Of course, when hardcoding the raw value it would be much better to just use .iOS directly but if the raw value comes from an external source we can try to make an enum with the value we received. If this works, we get an enum case back and if not, we get nil. This happens when we pass a raw value that’s not defined on the enum.

The last thing I’d like to show you before we talk about up and downside of enums is defining an enum with an associated value.

An example of such an enum is Swift’s built-in Result type:

enum Result<Success, Failure: Error> {
    case success(Success)
    case failure(Failure)

This enum uses generics to allow developers to use custom values for Success and Failure but you can also define an enum without generics for associated values. For example:

enum Animation {
  case none
  case easeIn(duration: CGFloat)
  // ...

With this Animation enum we can pass different animation configurations that are all grouped as possible values under a single type. This is super convenient!

If you get to a point where you’d like to compare some value to an enum case that has an associated value, you’ll want to read up on if case let syntax using this post I have on that topic.

Now that you know a bit about what enums are, let’s discuss when it makes sense to use them.

Knowing When to Use an Enum

Enums are ideal for managing a set group of related values in a way that makes your code clearer and safer. Learning to recognize when an enum would make sense is a key skill that will truly help you to write better and safer code over time.

The list below can be used to help you figure out whether an enum fits your current use case:

  • Enums are perfect when a variable can only take a limited set of predetermined values. If you're dealing with options, states, or modes within your application that are finite and known, enums help enforce this constraint with the help of the compiler.
  • Enums are excellent for managing state in your applications. For instance, if you have a UI control with multiple states like active, inactive, disabled, etc., an enum ensures you handle all possible states while also preventing developers from passing impossible or incorrect states.
  • If you’re using constants that are closely related and should be grouped under a single type, enums make this organization clear and logical. For example, error types, configuration options, and other relatively short finite lists of values.

Over time you’ll grow more and more confident in your ability to know whether an enum makes sense for your use case. I think it’s important to understand that not everything can or should be represented as an enum.

For example, I think it’s wise to make sure that your enums are fairly small. An enum that holds dozens of cases is probably too large and you’re no longer grouping closely related values together. It could make sense to refactor your large list of cases into a smaller list that uses associated values to group sub-values together.

It’s also a good idea to keep a close eye on how Apple uses enums in Swift and SwiftUI themselves. Using enums for similar scenarios should give you some confidence that you’re choosing the right tool for the job.

And when in doubt, refer to the list above and trust your instincts; they might be better than you think.

Subscribe to my newsletter