Enumerations 101 In Swift

2015-12-23

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:

[sourcecode language=“objc”] enum Day { case Monday case Tuesday case Wednesday case Thursday case Friday case Saturday case Sunday } [/sourcecode] 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.

[sourcecode language=“objc”] enum Day { case Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } [/sourcecode] The use of enumerations is easy and help us to avoid common spelling errors since values are supported from Xcode’s code completion feature.

[sourcecode language=“objc”] let d1 = Day.Monday var d2: Day = .Tuesday d2 = .Friday [/sourcecode] 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:

[sourcecode language=“objc”] enum Day: Int { case Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } [/sourcecode] 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…

[sourcecode language=“objc”] print(“The raw value of Friday \Day.Friday.rawValue)”) // 5 [/sourcecode] 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:

[sourcecode language=“objc”] 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 [/sourcecode] 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:

[sourcecode language=“objc”] let firstDay = Day(rawValue: 1) [/sourcecode] 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?

[sourcecode language=“objc”] 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() [/sourcecode] After that, the logical progression it to think about computed properties. So, thinking about them the most obvious implementation will be the following:

[sourcecode language=“objc”] 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 [/sourcecode] 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:

[sourcecode language=“objc”] enum GradeClassification { case Fail(String) case Pass(Int) } [/sourcecode] 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:

[sourcecode language=“objc”] func classification(mark: Int) -> GradeClassification { if mark < 50 { return .Fail(“Need to resit in September”) } else { return .Pass(mark) } } [/sourcecode] Using a switch, with pattern matching, we can easily handle the situation. [sourcecode language=“objc”] switch classification(53) { case let .Fail(text): print(text) case let .Pass(mark): print(“Success, your mark is \mark)”) } [/sourcecode] and the output will be: Success, your mark is 53So 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 (Attachment missing: (Attachment missing: enumerations101)).