Book Image

Beginning Swift

By : Rob Kerr, Kåre Morstøl
Book Image

Beginning Swift

By: Rob Kerr, Kåre Morstøl

Overview of this book

Take your first foray into programming for Apple devices with Swift.Swift is fundamentally different from Objective-C, as it is a protocol-oriented language. While you can still write normal object-oriented code in Swift, it requires a new way of thinking to take advantage of its powerful features and a solid understanding of the basics to become productive.
Table of Contents (10 chapters)

Enums


Enums are frequently used in Swift to create custom data types that have a predefined set of possible values to select from. Enums serve to make code more readable and maintainable, and also provide compile-time checking for parameters and value assignments which yield higher quality, more robust code.

Many languages provide built-in enum features, and Swift's implementation of the enum is very similar to other languages. Swift does have some unique enum features, which we'll cover in this section.

Basic Enum Syntax

Consider the following code, which creates and uses a basic enum:

enum DayOfWeek {
    case monday, tuesday, wednesday, thursday, friday
}

var today = DayOfWeek.wednesday

if today == .friday {
    print("Today is Friday")
} else {
    print("Today is not Friday")
}

Defining the enum DayOfWeek declares a new data type, which can be used just like any other data type. Because the variable today is of the type DayOfWeek, which can only be assigned one of the seven listed values, we could not assign anything else. For example, the following code would generate a compile-time error, because Saturday is not included in the predefined values:

Var today = DayOfWeek.saturday

The preceding example illustrates the two most important advantages of enums:

  • Possible values are restricted to a predefined list, making assignment of invalid values something that is tested at compile time rather than at runtime.

  • Code that uses enums become self-documenting and easier to understand.

Enum with Raw Values

In the preceding enum example, the enum values (.monday, .tuesday, and so on) have no underlying data type. For example, we might want to calculate the day of week by subtracting the ordinal number for the today variable from .monday.

However, with the enum as defined, there is no numeric value associated, so the following code will fail to compile:

var nthDay = today - DayOfWeek.Monday

This code generates the following error:

Binary operator – cannot be applied to two 'DayOfWeek' operands

This is by design, because unlike some languages, a Swift enum need not be mapped to a native data type (and should not be, if there's no reason to do so).

However, Swift enums can be mapped to any underlying data type. In the following revision, we map the day of week to the Int data type, which enables the nth day of the week calculation mentioned above:

enum DayOfWeek: Int {
    case monday, tuesday, wednesday, thursday, friday
}

var today = DayOfWeek.Wednesday // DayOfWeek.wednesday
var nthDay = today.rawValue - DayOfWeek.monday.rawValue + 1 // 3
var tomorrow = DayOfWeek(rawValue: today.rawValue + 1) // DayOfWeek.thursday

In this case, all we needed to do was add a native data type (Int) to the enum declaration. The Swift compiler then holds a .rawValue property. When an enum has an underlying value, it also becomes possible to create an enum member by passing it to the rawValue: parameter of the enum initializer.

Note

Use care with raw values. Passing a rawValue: to an enum initializer that does not match a defined case within the enum results in the creation of a nil optional.

In the preceding example, we used Int as the raw value for the revised DayOfWeek enum. Swift allows any data type to serve as the underlying value of an enum. For example, we could use String instead of Int to enable the following use case:

enum DayOfWeek: String {
    case monday = "Monday"
    case tuesday = "Tuesday"
    case wednesday = "Wednesday"
    case thursday = "Thursday"
    case friday = "Friday"
    case saturday = "Saturday"
}

var today = DayOfWeek.Wednesday // DayOfWeek.wednesday
let dayString = today.rawValue  // "Wednesday"

In this section, we have looked at enums in detail. We saw its syntax and how to define an enum with raw values. We will now work through an activity where we will use enums to implement error codes.

Activity: Using Swift Enums

Enumerations are a powerful construct available in many programming languages. Enumerations make code more robust and easier for others to understand and maintain.

Use Xcode to define error codes using conventional error number techniques, and alternatives that use Swift enums.

  1. Launch Xcode as before, and create a new playground named Activity D - Using Numeric Types.playground.

  2. Add the following lines of code to create a set of error codes using simple integer values:

    // Store an error condition as an integer
    let success = 0
    let ioFailure = 1
    let timeoutFailure = 2
  3. Now create the same set of error codes using an enum without a raw value:

    // Store an error condition as an enum type
    enum Result {
        case success
        case ioFailure
        case timeoutFailure
    }
  4. Finally, create the same set again, this time using an enum with a raw Integer value associated with each result code:

    // Store an error condition as an enum type with raw value
    enum ResultWithRawValue: Int {
        case success = 0
        case ioFailure = 1
        case timeoutFailure = 2
    }
  5. Now let's use these error values by creating a new variable, assigning the ioFailure error condition to each one:

    let error1 = ioFailure
    let error2 = Result.ioFailure
    let error3 = ResultWithRawValue.ioFailure
  6. Finally, use the console print function to output the content of each error variable. Note how each one is represented to the console:

    // Now print out the error result from each case.
    print("File access resulted: \(error1)")
    print("File access resulted: \(error2)")
    print("File access resulted: \(error3)")
    print("File access resulted: \(error3.rawValue)")