Enum explained in-depth with examples in Swift

Enum usage in Swift: If case, guard case, fallthrough, and the CaseIteratable protocol. These are all terms which could sound familiar if you’ve worked a lot with enums in Swift. An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.

Let’s go over them in more detail.

Defining an enum

Chances are big that you’ve worked with enums before. Well-known enums like ContentMode and AnimationCurve allow you to use a specific type in a method or on an object.

enum AnimationCurve: Int {
    case easeInOut
    case easeIn
    case easeOut
    case linear
}

Enums can be defined in a list or on a single line:

enum AnimationCurve: Int {
    case easeInOut, easeIn, easeOut, linear
}

And they’re smart in matching their raw value type:

print(AnimationCurve.easeInOut.rawValue) // 0
print(AnimationCurve.easeIn.rawValue) // 1
print(AnimationCurve.easeOut.rawValue) // 2
print(AnimationCurve.linear.rawValue) // 3

Which can be handy if you’re using them, for example, with tracking events:

enum TrackingEvent: String {
    case loggedIn = "logged_in"
}

Note that cases are defined using a lowercase first. Until Swift 3.0 this was not the case.

Using an enum case is as simple as calling `TrackingEvent.loggedIn` or by making benefit of the Swift type system and using the shorter variant .loggedIn.

func track(_ event: TrackingEvent) {
    print("Tracked \(event.rawValue)")
}

track(.loggedIn) // Tracked logged_in

Iterating over all enum cases

Iterating over an enum or getting the total amount of cases is easy by making use of the CaseIterable protocol. The protocol defines a property allCases which is a collection type.

enum SocialPlatform: String, CaseIterable {
    case twitter
    case facebook
    case instagram
}

print(SocialPlatform.allCases) // twitter, facebook, instagram

This makes it possible to use functional methods like forEach, filter, and map.

Enums and Equatable

Swift 4.1 made it easier to compare enums. Nothing more needed than just defining your enum:

enum SocialPlatform {
    case twitter
    case facebook
    case instagram
}

let mostUsedPlatform = SocialPlatform.twitter

if mostUsedPlatform == .facebook {
    print("Fake news")
} else {
    print("You're totally right!")
}

This does not work for enums with values. In that case, you have to inherit from the Equatable protocol.

enum TimeInterval: Equatable {
    case seconds(Int)
    case milliseconds(Int)
    case microseconds(Int)
    case nanoseconds(Int)
}

if TimeInterval.seconds(1) == .seconds(2) {
    print("Matching!")
} else {
    print("Not matching!")
}

If case, guard case without Equatable

If your enum contains values of many different types, it might not be so easy to inherit from the Equatable protocol. This is the case when the inner types are not conforming to Equatable. It’s also the case with the popular Result enum which contains a generic value.


enum Result {
    case success(Value)
    case failure(Error)
}

extension Result {
    /// The error in case the result was a failure
    public var error: Error? {
        guard case .failure(let error) = self else { return nil }
        return error
    }

    /// The value in case the result was a success result.
    public var value: Value? {
        guard case .success(let value) = self else { return nil }
        return value
    }
}

The extension defines two properties to easily access the value and error. Guard case can be used just like if case, which makes it possible to read the inner value of the enum case.

Using fallthrough in a switch statement

The fallthrough keyword causes program execution to continue from one case in a switch statement to the next case. This can be handy if you’re printing out a type like in the following example:

enum ImageType {
    case jpeg
    case png
    case gif
}

let imageTypeToDescribe = ImageType.gif

var description = "The image type \(imageTypeToDescribe) is"

switch imageTypeToDescribe {
case .gif:
    description += " animatable, and also"
    fallthrough
default:
    description += " an image."
}

print(description) // The image type gif is animatable, and also an image.

Option sets in Swift

Looking similar to enums in usage you can also define an OptionSet in Swift. Read more on this topic in OptionSet usage in Swift like NS_OPTIONS.