Mastering Swift
上QQ阅读APP看书,第一时间看更新

Enumerations

Enumerations (or otherwise known as enum) are a special data type that enables us to group-related types together and use them in a type safe manner. For those of us who are familiar with enums from other languages, such as C or Java, enums in Swift are not tied to integer values. The actual value of an enum (known as the raw value) can be a String, a Character, an Integer or a Floating-point value. Enums also support features that are traditionally supported only by classes such as computed properties and instance methods. We will discuss these advanced features in depth in classes and structures chapter. In this section, we will look at the traditional enum features.

We will define an enum that contains the list of planets like this:

enum Planets {
  case Mercury
  case Venus
  case Earth
  case Mars
  case Jupiter
  case Saturn
  case Uranus
  case Neptune
}

The values defined in an enum are considered to be the member values (or simply the members) of the enum. In most cases, you will see the member values defined like the preceding example because it is easy to read; however, there is a shorter version. This shorter version lets us define multiple members in a single line, separated by commas, like the following example shows:

enum Planets {
  case Mercury, Venus, Earth, Mars, Jupiter
  case Saturn, Uranus, Neptune
}

We can then use the Planets enum like this:

var planetWeLiveOn = Planets.Earth
var furthestPlanet = Planets.Neptune

The type for the planetWeLiveOn and furthestPlanet variable is inferred when we initialize the variable with one of the member values of Planets. Once the variable type is inferred, we can then assign a new value without the Planets prefix, like this:

planetWeLiveOn = .Mars

We can match an enum value using the traditional equals (==) operator, or we could use a switch statement. The following example shows how to use the equals operator and the switch statement with an enum:

if planetWeLiveOn == .Earth {
  println("Earth it is")
}

switch planetWeLiveOn {
case .Mercury:
  println("We live on Mercury, it is very hot!")
case .Venus:
  println("We live on Venus, it is very hot!")
case .Earth:
  println("We live on Earth, just right")
case .Mars:
  println("We live on Mars, a little cold")
default:
  println("Where do we live?")
}

Enums can come prepopulated with raw values, which are required to be of the same type. This means that we can define our enum to contain string, character, integer, or floating-point values, but all of the members must be defined as the same type. The following example shows how to define an enum with string values:

enum Devices: String {
  case iPod = "iPod"
  case iPhone = "iPhone"
  case iPad = "iPad"
}
println("We are using an " + Devices.iPad.rawValue)

The preceding example creates an enum with three Apple devices. We then use the rawValue property to retrieve the raw value for the iPad member of the Devices enum. This example will print a message saying We are using an iPad.

Let's create another Planet's enum, but this time, assign numbers to the members as follows:

enum Planets: Int  {
  case Mercury = 1
  case Venus
  case Earth
  case Mars
  case Jupiter
  case Saturn
  case Uranus
  case Neptune
}
println("Earth is planet number " + String(Planets.Earth.rawValue))

The big difference between the two enum examples is that in the second example we only assign a value to the first member (Mercury). If integers are used for the raw values of an enum, then we do not have to assign a value to each member. If no value is present, the raw values autoincrement.

In Swift, enums can also have associated values. Associate values allow us to store additional information along with member values. This additional information can vary each time we use the member. The additional information can also be of any type, and the types can be different for each member. Let's take a look at how we might use associate types by defining a Product enum, which contains two types of products.

enum Product {
  case Book(Double, Int, Int)
  case Puzzle(Double, Int)
}
var masterSwift = Product.Book(49.99, 2015, 310)
var worldPuzzle = Product.Puzzle(9.99, 200)

switch masterSwift {
case .Book(let price, let year, let pages):
  println("Mastering Swift was published in \(year) for the price of (price) and has \(pages) pages")
case .Puzzle(let price, let pieces):
  println("Master Swift is a puzze with \(pieces) and sells for (price)")
}

switch worldPuzzle {
case .Book(let price, let year, let pages):
  println("World Puzzle was published in \(year) for the price of (price) and has \(pages) pages")
case .Puzzle(let price, let pieces):
  println("World Puzzle is a puzze with \(pieces) and sells for (price)")
}

In the preceding example, we begin by defining a Product enum with two members, Book and Puzzle. The Book member has an associated value of Double, Int, Int, and the Puzzle member has an associated value of Double, Int. We then create two products masterSwift and worldPuzzle. We assign the masterSwift variable a value of Product.Book with associated values of 49.99, 2015, 310. We then assign the worldPuzzle variable a value of Product.Puzzle with associated values of 9.99, 200.

We can then check the Products enum using a switch statement, as we did in some of the preceding enum examples. We also extract the associated values within the switch statement. In the preceding example, we extracted the associated values as constants with the let keyword, but you can also extract the associated values as variables with the var keyword.

If you put the preceding code into a Playground, the following results will be displayed:

"Master Swift was published in 2015 for the price of 49.99 and has 310 pages"
"World Puzzle is a puzze with 200 and sells for 9.99"