Enumerations - OBJECT-ORIENTED PROGRAMMING - Understanding Swift Programming: Swift 2 (2015)

Understanding Swift Programming: Swift 2 (2015)

PART 2: OBJECT-ORIENTED PROGRAMMING

15. Enumerations

Enumerations can be one of the more confusing aspects of Swift. This isn't particularly surprising. Enumerations really combine two capabilities. One capability allows the creation of a custom data type that contains a predefined set of values. The other capability uses this custom data type in ways that are very much like a class. It is the latter capability that causes the confusion, since it seems so different from the basic idea of enumeration, and because programmers new to it have trouble with something that seems to have some of the characteristics of a class (but not some of the expected capabilities such as stored properties) and is overlaid on top of the idea of enumeration values.

In this chapter I will describe only enumerations in their role as predefined sets of values. In a later chapter (Chapter 31, "Enumerations Revisited") I will describe how enumerations are used in ways that are indeed very much like classes.

An enumeration, according to Apple, "defines a common type for a group of related values and enables you to work with these values in a type-safe way within your code." Let's take these one by one.

Defining a Common Type for a Group of Related Values

An enumeration in Swift defines a new (custom) type with a name that refers to a set of possible values. (The word enumerate means to "name one by one" or "to specify, as in a list".)

To define an enumeration, you use the keyword enum and follow it by the name of the new type and a list of the allowed values. The list is contained within braces and the keyword case appears before each value:

enum DayOfTheWeek {

case Sunday

case Monday

case Tuesday

case Wednesday

case Thursday

case Friday

case Saturday

}

This data type DayOfTheWeek defines all of the possible values allowed for the day of the week: Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, and Saturday.

A variable declared with a type of DayOfTheWeek that has one of the possible values for DayOfTheWeek stored in it can be created like this:

var today = DayOfTheWeek.Friday

You can also refer to it in a shorthand version using only the reference to the value, if you explicitly declare the type of the variable:

var today: DayOfTheWeek = .Friday

There's also an alternative syntax that requires only a single case statement:

enum DayOfTheWeek {

case Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday

}

The values, also known as members, or member values, represent related concepts. These must be values that will not change during the lifetime of the program, since they are fixed by the enum definition. The days of the week or the months of the year are good examples of enumerations, since they do not change.

Working with the Values in a Type-Safe Way

Apple's definition of an enumeration also mentioned work with these values in a type-safe way. What I believe that they mean by this is the way that Swift handles enumerations, in contrast with the way it is done in Objective-C. In Objective-C and C, enumerations are actually integers, with each name really just an alias for an integer.

Swift defines enumeration values differently. In the example above, where today is set to the value Friday (referred to as .Friday just as shorthand for DayOfTheWeek.Friday), the value really is Friday. It is not an integer that stands in for Friday, nor is it the string "Friday". It is the value Friday, which by defining it as an enumeration makes it a symbol that is not much different from var or class or func or true or false.

Defining a type with values like this makes the code safer. If the day of the week is instead represented by an integer (0 to 6, say), it would be possible for errant code to write an incorrect integer value (say 764) into the variable that stored the value representing the day of the week. This can't be done if the allowable values are specifically defined.

Using enumerated values, which are chosen to be easily understandable by humans, also makes the code more readable. And more readable code is itself safer.

Raw Values

It is sometimes the case that you want to use some representation in addition to the defined values of the enumeration. In particular, you might want to use an integer, for example, to allow you to store something in an array using the integer as an index. Thus we might want to sometimes use the integer value 5 instead of the enumeration member value Friday.

We can do this by defining what are known as raw values. These are defined as part of the original definition of the enumeration. For example, if we wanted to include integers as part of our DayOfTheWeek enumeration, we could do it as follows:

enum DayOfTheWeek: Int {

case Sunday = 0

case Monday = 1

case Tuesday = 2

case Wednesday = 3

case Thursday = 4

case Friday = 5

case Saturday = 6

}

This definition is just like the original except that we have added two things. First, just after the name of the enumeration, we add a colon (":") and the type of the raw value. We are using an integer here, but we could also use a string, character, or any of the integer or floating point number types. And second, for each enumeration value that we define, we follow it with an equals sign and a value that will become the raw value.

Each raw value must be unique. Once a raw value for an enumeration member is set, it cannot be changed.

To get the raw value, we access the rawValue property of a particular member:

var today = DayOfTheWeek.Friday

print(today.DayOfTheWeek.Friday.rawValue) // Prints: 5

We actually didn't have to define all of the integer values the way we did in our definition of an enumeration with raw values. For the special case of an integer, all we need to do is to specify the first value of the integer, and the compiler will take care of the result, incrementing each value:

enum DayOfTheWeek:Int {

case Sunday = 0

case Monday // Will be 1

case Tuesday // Will be 2

case Wednesday // Will be 3

case Thursday // Will be 4

case Friday // Will be 5

case Saturday // Will be 6

}

Using Enumerations with a Switch Statement

It is quite common to use enumerations with switch statements. This makes it easy to perform different actions depending upon the value of the enumeration. The result is also code that is very readable. An example is:

enum DayOfTheWeek {

case Sunday

case Monday

case Tuesday

case Wednesday

case Thursday

case Friday

case Saturday

}

var today = DayOfTheWeek.Friday

switch(today) {

case: .Sunday {

print("Today is Sunday")

}

case: .Monday {

print("Today is Monday")

}

case: .Tuesday {

print("Today is Tuesday")

}

case: .Wednesday {

print("Today is Wednesday")

}

case: .Thursday {

print("Today is Thursday")

}

case: .Friday {

print("Today is Friday")

}

case: .Saturday {

print("Today is Saturday")

}

No default is provided because the only possible values of dayToday, if it has the type DayOfTheWeek, are those values covered by the case statements in the switch statement.

Hands-On Exercises

Go to the following web address with a Macintosh or Windows PC to do the Hands-On Exercises.

For Chapter 15 exercises, go to

understandingswiftprogramming.com/15