Working with Enumerations to Consolidate Values - Using Components and Subcomponents - Swift For Dummies (2015)

Swift For Dummies (2015)

Part IV. Using Components and Subcomponents

Chapter 17. Working with Enumerations to Consolidate Values

In This Chapter

arrow Using raw values with enumerations

arrow Combining enumerations with switches

arrow Adding functions to enumerations

Swift takes structures and enumerations far beyond their roots in C and C-like languages. Structure, classes, and enumerations all can contain functions as well as data elements. They also can all adopt protocols.

This chapter shows you how to use Swift enumerations both in traditional ways and in ways that work alongside new Swift features such as embedded functions and raw values.

icon tip For more on structures, see Chapter 15 and Chapter 16.

Using Enumerations with Swift

In the world of Swift, you may want to rethink how you use enumerations.

Whereas in C, structures and enumerations are often used as simple types (that is, more or less as a way of saving keystrokes or organizing the code), structures, enumerations, and classes in Swift are all object-oriented first-class types. Accordingly, then, in the world of Swift, it is common to refer to instances of structures and enumerations, as well as instances of classes.

When an instance of a structure or enumeration is passed from one code component to another, it is passed by value, whereas instances of classes are passed by reference. Putting it another way, instances of structures and enumerations are placed on the stack, whereas instances of classes are placed on the heap.

For developers interested in what this means to them and their app, it means that when you pass a unique copy of a structure or enumeration around in your app, that instance is actually moved around, and each function or other segment of code that touches it touches the instance that moves. When one segment of code makes a change to the instance data, it doesn’t affect other instances.

When you pass an instance of a class, that instance is shared among the sections of code to which it is passed (that’s because typically behind the scenes you only pass a pointer to the instance). If you make a change to a property of a class instance, however, everyone who is using that instance sees that change.

Understanding Traditional C Structures and Enumerations

Before moving on to Swift, it’s worthwhile reviewing some classic examples from C. Enumerations were not in the classic reference (The C Programming Language by Brian Kernighan and Dennis Ritchie), but they were added later on. They are also used in conjunction with a structure. Here is an example of an enum and a structure in C that uses it.

enum priority {
    urgent,
    medium,
    low,
    not assigned
};

enum priority myPriority;

myPriority = low;

The enum priority can take any of the four values. A variable like myPriority can be assigned any of those values. The values can have integer values assigned to them, and, in fact, integer values starting at zero are used by default.

Many developers are used to using an enum structure to declare constants so that related constants are all together.

Exploring Swift Enumerations

When you add Swift’s features, enumerations become much more class-like. They are no longer just collections of constants because they can now have their own properties and functions.

Here’s what a Swift enumeration can look like:

enum ParkPlace: Int {
    case park, pool, bars, track
}

With a bit of respacing, however, this can look very much like a classic C enum:

enum ParkPlace: Int {
    case park
    case pool
    case bars
    case track
}

You can assign an enumeration value to a variable in Swift using code like this:

let myPlace = ParkPlace.park

If you include this assignment and then try to print out myPlace in a playground, you’ll see the value “Enum Value” at the right.

icon tip Refer to Figure 17-1 for examples of enumerations in playgrounds using variations on the code in this section.

image

Figure 17-1: Using a playground to explore enumerations.

You can reveal the underlying value of an enumeration using the intrinsic rawValue, as in this line of code:

println (myPlace.rawValue)

The result will be “0” because by default, enumeration raw values start at zero and the result of a println function is a string (hence the quotation marks).

You can assign your own raw values to enumeration cases. For example, you could arrange the declaration like this:

enum ParkPlace: Int {
    case park
    case pool = 25
    case bars
    case track
}

Here, .park will still be 0 by default. However,.pool is now set to 25, and the sequence continues from there. Thus, the following code snippet will print 26. If you were to set bars to 99, track would automatically become 100.

let myPlace = ParkPlace.bars
println (myPlace.rawValue)

It is common to use strings in an enumeration. Here is a sample in which the enumeration cases have strings assigned to them.

enum Place: String {
  case
    park = "park",
    pool = "swimming pool",
    bars = "climbing bars",
    track1 = "running track",
    track2 = "walking track"
}

Note in this and the previous examples that there is a distinction between the case elements which are not quoted strings and the associated values which are strings. Note also that in your code the case elements start with a period when you use them. The period is not used in the declaration.

.track would print 27.

Working with members of an enumeration

Inside an enumeration, you can declare variables or constants. As you can see in Figure 17-1 and Listing 17-1, the enumeration contains a static variable consisting of an array with the five cases of the enumeration. Work through the following steps to explore the code you see in Figure 17-1 and Listing 17-1.

Listing 17-1: Creating an Enumeration with a Member

enum Place: String {
  case
    park = "park",
    pool = "swimming pool",
    bars = "climbing bars",
    track1 = "running track",
    track2 = "walking track"
  
  static let facilities = [park, pool, bars, track1,
    track2]
  
}

1. Declare the Place enumeration.

As discussed in the previous section, it has five cases.

2. Declare a static member of the enumeration.

Its name is facilities, and it is an array consisting of the five enumeration cases.

Note that the elements of the array are the enumeration cases: They are not strings and they are not quoted.

3. Create a variable e and set it to the raw value of the pool case of the Place enumeration.

You are using the declaration and not an instance of the enumeration. As you see in Figure 17-1, it has the value “swimming pool” with the associated value of the case pool.

4. If you print it, you’ll see it identified only as an Enum Value.

5. Use fast enumeration to loop through the facilities array using amenity as the loop variable.

You’ll see in the playground that the println statement executes five times.

6. Create a String variable called result and set it to a blank string.

7. In another fast enumeration loop, add each raw value (string) to result along with a comma and a blank.

8. Print result.

This type of code could be used to create checkboxes for all the values of the enumeration.

That use of fast enumeration in Step 8 would be the reverse of what is often done when you draw the interface and then declare the variables behind checkboxes or other user interface elements. In this case, you define the enumeration and its cases and then write code to create the interface elements. Try it and you’ll be convinced that it’s faster.

Working with a function inside an enumeration

With the same basic code, you can add a function to the enumeration. This is something you haven’t seen in C and perhaps not in other languages either. It’s a new way of looking at enumerations.

Adding a simple function to an enumeration

Here is the function that’s added to the enumeration. You can place it anywhere (except, of course, not in the middle of the case):

func enumFunction () -> Int {
    return -17
  }

The function is named enumFunction and it returns an Int with the value of –17. You can access this function from any instance of the enumeration. Here’s one example:

let i = Place.bars.enumFunction()

You may be thinking, “Wait a moment. That enumeration is typed as String and so it must return a String.”

That’s true, but you’re not referring to the value returned by the enumeration. You are asking a member of the enumeration (not even an instance of the enumeration) to return the result of enumFunction, which is declared as Int.

Adding a switch statement to a function inside an enumeration

Swift enumerations are often used in conjunction with switch statements. Here is a function to place inside the enumeration that contains a switch statement. When you have an instance of an enumeration (or just the enumeration itself), you can call an internal function from an element just as you saw in the preceding code snippet. And, like the preceding code snippet, the result returned by the function need not be the same type as the type of the enumeration.

In the following code a function that returns a String is based on the result of a switch statement that uses the elements of the enumeration. Note that the elements of the switch are not strings (note the absence of quotation marks and the presence of the leading periods in the case names).

Experiment with this code, and you’ll see that if you set the type of the enumeration to Int (or Double or anything other than String) the function will still return a String. That’s the result of the function and not the type of the enumeration. This is a very useful technique to use, and many developers find that it dramatically reduces the code they have to write. (Those if-then-else-if statements inside switch case statements can be omitted, as can switch statements within case statements.)

func enumChoiceFunction () -> String {
    switch self {
    case .track1, track2:
      return "running or walking"
    case .park:
      return "Walking, sitting on a bench, feeding birds"
    default:
      return "enjoying nature"
    }
  }

Figure 17-2 shows the code described in this section. The code itself is provided in Listing 17-2 and Figure 17-3.

image

Figure 17-2: Using functions inside an enumeration (top).

image

Figure 17-3:> Results of functions within an enumeration (bottom).

Listing 17-2: Using a Simple and a Complex (switch) Function inside an Enumeration

enum Place: String {
  case
    park = "park",
    pool = "swimming pool",
    bars = "climbing bars",
    track1 = "running track",
    track2 = "walking track"
  
  static let facilities = [park, pool, bars, track1, track2]
  
  func enumFunction () -> Int {
    return -17
  }
  
  func enumChoiceFunction () -> String {
    switch self {
    case .track1, track2:
      return "running or walking"
    case .park:
      return "Walking, sitting on a bench, feeding birds"
    default:
      return "enjoying nature"
    }
  }
}
let i = Place.bars.enumFunction()
  
let e = Place.pool.rawValue
  
println (Place.pool)
  
let x = Place.track1.enumChoiceFunction()
  
var result: String = ""
  
for amenity in Place.facilities {
  result = result + amenity.rawValue + ", "
}
  
println (result)