Enumerations 101 in swift

This content has 9 years. Please, read this page keeping its age in your mind.

Don’t underestimate the enumerations in Swift. If you come from C or objective C there is a nice surprise for you. Enumeration are not based on integers, can have methods, initialisers, computed properties and conform to protocols. Additionally, we are going to learn about associated values as well, a powerful feature that is engaged in error handling too.

Classic cases to use enumerations are when you have a well defined set of values and you want to group them as a type. For example, the compass points (north, south, east and west), the card suits (spades, hearts, diamonds and clubs) or the days of the week.

The syntax of enumeration is simple. Use the keyword enum, followed by the name of the enumeration and curly braces with the implementation. To illustrate this:

enum Day {
    case Monday
    case Tuesday
    case Wednesday
    case Thursday
    case Friday
    case Saturday
    case Sunday
}

In case that we have many values and we don’t want to repeat the keyword case we can place all the values in one case separated with comma.

enum Day {
    case Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}

The use of enumerations is easy and help us to avoid common spelling errors since values are supported from Xcode’s code completion feature.

let d1 = Day.Monday
var d2: Day = .Tuesday

d2 = .Friday

Everything is straightforward. The type reference works seamlessly and since compiler knows about the type we can only use the dot and the value and not the entire type dot value syntax.

In swift enumerations are not based on integers. They exist on their own. However, it is possible to assign types if this is something convenient for our code. So, the Day example can be like that:

enum Day: Int {
    case Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}

Notice the changes: after the name we should add the semicolon followed by the type. Then, in each member value assign an value of the predefined type. In the case of integers, it is possible to assign only the initial value and the rest is incremented by one.

What about the raw value? Well, this is the value that is assigned if we have associated a type, like before. So the raw value of Friday is…

print("The raw value of Friday \(Day.Friday.rawValue)") // 5

Exactly! Using the property rawValue of the member we can have it.

As I said, enumerations can also support initialisers. So think about the possibility to create a new instance of the enum type with a default value. The way is similar to what you know about the classes and the structs and looks like:

enum Day: Int {
    case Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday

    init() {
        self = .Monday
    }
}

let myDay = Day() // This will assign .Monday to myDay const

You just use the classic init() method and you assign an initial value to the actual instance using, what else, the self keyword.

Raw values are useful in initialisation as well. We can use them by employing the following way:

let firstDay = Day(rawValue: 1)

This will give us the first day of the week, Monday. But be careful, this is a failable initialiser and returns optional, since there is no guarantee that the raw value corresponds to a member value.

Talking about raw values, methods come to my thoughts. So another classic and useful example. How about having a method to calculate the days till weekend?

enum Day: Int {
    case Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday

    func tillWeekend() -> Int {
        return Day.Friday.rawValue - self.rawValue
    }
}

let today = Day.Monday
let val = today.tillWeekend()

After that, the logical progression it to think about computed properties. So, thinking about them the most obvious implementation will be the following:

enum Day: Int {
    case Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday

    var daysTillWeekend: Int {
        return Day.Friday.rawValue - self.rawValue
    }
}

let today = Day.Monday
let val = today.daysTillWeekend

There is another exciting feature about enumerations in swift. Instead of having a set of values as members, we can have associated values of other types alongside these case values. One example will come for the rescue. Lest say that we have an enumeration for classification of the marks in university units. If you have more 50 you pass, otherwise fail and resit is on your way. So take a look in this definition:

enum GradeClassification {
    case Fail(String)
    case Pass(Int)
}

In case of fail we send a String informing about the resit. On the other hand, we send the actual mark. A function to do all the dirty work look like this:

func classification(mark: Int) -> GradeClassification {
    if mark < 50 {
        return .Fail("Need to resit in September")
    } else {
        return .Pass(mark)
    }
}

Using a switch, with pattern matching, we can easily handle the situation.

switch classification(53) {
case let .Fail(text):
    print(text)
case let .Pass(mark):
    print("Success, your mark is \(mark)")
}

and the output will be:
Success, your mark is 53

So again, the outcome will the one case or the other. The associated values however give us great flexibility and become necessary in error handling when we define error types for the related procedures.

Happy about the enumerations? Experiment more and use them in our code!
If you want the playground of this lesson, you can find it here.