© Radoslava Leseva Adams and Hristo Lesev 2016

Radoslava Leseva Adams and Hristo Lesev, Migrating to Swift from Flash and ActionScript, 10.1007/978-1-4842-1666-8_20

20. Control Flow

Radoslava Leseva Adams and Hristo Lesev2

(1)London, UK

(2)Kazanlak, Bulgaria

We have so far covered types and operators in Swift and you know how to declare variables and constants. Now is time to go over how you can control the execution of your code. It’s all about loops, conditional statements, keywords for changing the course of action, and Christmas carols . . .

Loops

It is Christmas as I am writing this and the shops and cafés around me are playing the obligatory Christmas carols in a loop. One in particular strikes me as an example I could steal to play with and show you how loops work in Swift. It’s called The Twelve Days of Christmas and goes like this:

On the first day of Christmas my true love sent to me

a partridge in a pear tree.

On the second day of Christmas my true love sent to me

two turtle doves

and a partridge in a pear tree.

On the third day of Christmas my true love sent to me

three French hens,

two turtle doves

and a partridge in a pear tree.

. . . and so on until we collect a whole menagerie on day 12.1 The song has a simple structure, which iterates through a set of days, 12 to be precise. Each iteration follows the same pattern: a day is enumerated, a gift is associated with it, and then another iteration is done, this time backward, through all of the accumulated gifts thus far.

The examples I am going to run you through will try to build the lyrics of the song, using for or while loops. For that purpose, let us declare all the Christmas gifts in an array first. We will then iterate over that array in various different ways. Listing 20-1 declares a constant array, called christmasGifts, which contains the description of the gifts for each day. We will also declare another constant: christmasDays to keep the number of days to iterate through, which equals the number of items in the christmasGifts array.

Listing 20-1. Declaring an Array of Christmas Gifts, Which We Will Use in the Next Examples
// An array of Christmas gifts
let christmasGifts = ["a partridge in a pear tree",
                      "two turtle doves",
                      "three french hens",
                      "four calling birds",
                      "five gold rings",
                      "six geese a-laying",
                      "seven swans a-swimming",
                      "eight maids a-milking",
                      "nine ladies dancing",
                      "ten lords a-leaping",
                      "eleven pipers piping",
                      "twelve drummers drumming"]


let christmasDays = christmasGifts.count

for

We will introduce loops with something that will look familiar from ActionScript but is on its way out in Swift: the straightforward for loop. It works and almost looks like its ActionScript counterpart, except that you do not need to enclose the definitions after the if statement, the so-called initialization, condition, and afterthought, in parentheses. Listing 20-2 demonstrates the syntax. This example declares a variable, called day, which is initialized with a value of 1 and keeps incrementing after each execution of the loop until it reaches the value of christmasDays. In the body of the loop day is used to print out the day and what gift was received on it. The corresponding gift is effectively the value of christmasGifts[day - 1], as Swift arrays, like their ActionScript cousins, have indices starting at 0.

Listing 20-2. A for loop with a Counter
// Define a counter, named day
// and use it to iterate over the christmasGifts array:
for var day = 1; day <= christmasDays; day += 1 {
    print("On the (day) day of Christmas my true love sent to me")


    // Like in ActionScript, arrays in Swift are indexed from zero.
    print("(christmasGifts[day - 1]) ")
}


// output:

//On the 1 day of Christmas my true love sent to me
//a partridge in a pear tree


//On the 2 day of Christmas my true love sent to me
//two turtle doves


//On the 3 day of Christmas my true love sent to me
//three french hens


// ...

The output of this loop leaves a few things to be desired. First, the verses are not quite right: we are missing the iteration through the accumulated gifts. Second, it would be nice if we had “1st” instead of “1”, “2nd” instead of “2,” and “3rd,” instead of “3” when we enumerate the days of Christmas. We will tackle both of these shortcomings in the course of the chapter.

Caution

This form of the for loop is deprecated in Swift 2.2 and will not be part of Swift 3. Its substitute, the for-in loop is better suited for most situations where you will need to loop through items: iterating through collections or going through a range of values. More on that in the next section.

for-in

The for-in flavor of the for loop is a bit more versatile than its ActionScript for..in and for each .. in counterparts and offers you more ways of counting or iterating through items.

Let us start with an exact equivalent of the loop in the last example, but using more concise syntax. Instead of for initialization ; condition ; afterthought the code in Listing 20-3 declares a loop with the following anatomy: for counter in range, where range goes from 1 to the value of christmasDays and counter loops through that range. Note that the bounds of the range don’t have to be constants. Both this loop and the for loop in Listing 20-2 produce the same result.

Note

The range declaration in the example below uses the closed range operator, which we covered in Chapter 18.

Listing 20-3. A for-in Loop, Which Counts Within a Range
for day in 1...christmasDays {
    print("On the (day) day of Christmas my true love sent to me")
    print("(christmasGifts[day - 1]) ")
}


// output:

//On the 1 day of Christmas my true love sent to me
//a partridge in a pear tree


//On the 2 day of Christmas my true love sent to me
//two turtle doves


//On the 3 day of Christmas my true love sent to me
//three french hens


// ...

Ignoring the Counter

Instead of the full version of the syntax, for counter in range, you can use for _ in range. The underscore tells the compiler that you don’t care for the values of the counter variable and want to ignore them. The next example illustrates that, if not in the most efficient way. It ignores the values that the for-in loop provides and instead uses a variable outside the loop, named day, which gets incremented with each iteration. The numberOfGifts variable accumulates the values that day goes through and in the end contains the total number of Christmas gifts in the song (Listing 20-4).

Listing 20-4. You Can Ignore the Counter in a for-in Loop
var numberOfGifts = 0
var day = 1


// Ignore the counter
for _ in 1...christmasDays {
    day += 1
    numberOfGifts += day
}
print("I received (numberOfGifts) gifts for Christmas.")


// output: I received 78 gifts for Christmas.

Iterating Through Items in an Array

Straying from our mission to build that Christmas carol for a just bit longer (don’t worry, we’ll get there), let me show you how you can enumerate the items in an array, using a for-in loop. The code in Listing 20-5 prints out a bullet list of the items in the christmasGifts array. Does that look familiar? It should: bar a couple of extra parentheses, you would do exactly the same thing in ActionScript, using a for each ... in loop.

Listing 20-5. A for-in Loop That Enumerates the Items in an Array
print("I received a whole menagery for Christmas:")
for gift in christmasGifts {
    print("• (gift)")
}


// output:

//I received a whole menagery for Christmas:
//• a partridge in a pear tree
//• two turtle doves
//• three french hens
//• four calling birds
//• five gold rings
//• six geese a-laying
//• seven swans a-swimming
//• eight maids a-milking
//• nine ladies dancing
//• ten lords a-leaping
//• eleven pipers piping
//• twelve drummers drumming

Looping Backward Through a Range

Let us go back to what we set out to do in the beginning of this chapter, which was to have the lyrics of The Twelve Days of Christmas printed out by a loop in Swift. What we achieved so far in Listing 20-2 and Listing 20-3 was to have the beginning of each verse printed out by a for or a for-in loop. The next step is to add the missing lines to the verses: every verse will be a line longer than the previous one and will enumerate backward the gifts received so far.

To build a backward-iterating loop , we will take advantage of a method that you can call on integer types in Swift.2 The method is called stride(to: end_value, by: step) and produces a sequence of values ranging from the value of the number you call the method on to end_value, spaced by step (Listing 20-6).

Listing 20-6. Producing a Backward-Counting for-in Loop
// The stride(to:_, by:_) method
// lets you count backwards from the current value of day
for dayBackwards in day.stride(to: 0, by: -1) {
    // compose verse here
}

To get the verses of the song composed properly, we need to nest this loop inside the loop, which enumerates each day from 1 to the value of christmasDays: the outer loop will go through the days and the inner loop through the gifts that have been accumulated on each day.

Before we do that, however, let us take care of some extra business: when gifts are enumerated, each line describing a gift requires different punctuation, depending on which verse it appears in and what gift is being described. For example, we want to add a full stop to the last line of each verse: “a partridge in a pear tree.” On the days after day one this last line will also have an extra “and” at the start and will appear as “and a partridge in a pear tree.” In addition, we want the lines about the gifts to be separated by commas, except the last two because of that extra “and” between them. Listing 20-8 takes care of all this in a function that we will call composeVerseLine. It takes the index of the day the verse is about (day), a gift description (gift), and a Boolean parameter (needsPrefix), whose job is to help us decide whether the line being composed needs an “and” prepended to it (Listing 20-7).

Listing 20-7. Taking Care of the Punctuation in the Verse Lines
// This function composes a song line, which describes a gift.
func composeVerseLine
        (day: Int, gift: String, needsPrefix : Bool = true) -> String {
    // From the second day onwards, we want to prepend "and"
    // at the start of the last verse, in order to get
    // "and a partridge in a pear tree".
    let versePrefix = (1 == day && needsPrefix) ? "and " : ""


    // We want every line that describes a gift,
    // but the last two, to end with a comma.
    // The penultimate line doesn't need punctuation
    // and the last one needs a fullstop.
    let versePostfix = 1 == day ? "." : (2 == day ? "" : ",")


    // Finally, ready to assemble the line:
    return "(versePrefix)(gift)(versePostfix)"
}
Tip

The assignments to versePrefix and versePostfix use the ternary conditional operator (a ? b : c). For details on it and how it compares to its ActionScript counterpart see Chapter 18.

We can now put the two loops together and have them output the lyrics of the song (Listing 20-8).

Listing 20-8. Two Nested for-in Loops
for day in 1...christmasDays {
    print(" On the (day) day of Christmas my true love sent to me")


    // Enumerate the days backwards, starting with the current day:
    for dayBackwards in day.stride(to: 0, by: -1) {
        // Call the function we defined that adds punctuation to each line:
        let verseLine =
          composeVerseLine(dayBackwards,
            gift: christmasGifts[dayBackwards - 1], needsPrefix: day > 1)
        print("(verseLine)")
    }
}


// output:

//On the 1 day of Christmas my true love sent to me
//a partridge in a pear tree.


//On the 2 of day Christmas my true love sent to me
//two turtle doves
//and a partridge in a pear tree.


//On the 3 of day Christmas my true love sent to me
//three french hens,
//two turtle doves
//and a partridge in a pear tree.


// ...

Now that’s more like it: the song lyrics look almost exactly as we would expect to see them. Except for the annoying “On the 1 day,” “On the 2 day,”. . . We will take care of these in due course.

while

The while loop in Swift will be like an old friend to you if you are used to while loops in ActionScript. And if you have avoided them altogether, I can’t blame you: it is usually easier to go into an infinite loop with while than with for, although with perseverance you can achieve anything. The syntax you use in Swift looks like this: while condition { statements }. The loop will repeat the statements in the curly brackets as long as condition evaluates to true.

Listing 20-9 continues the Christmas theme we started when we went over for loops. This time we will be printing the verses backward, starting from the twelfth day of Christmas and going down to the first.

Listing 20-9. Printing Out Verses with a while Loop
// Redefine christmasGifts as a variable, so we can change its size:
var christmasGifts = ["a partridge in a pear tree",
                      "two turtle doves",
                      "three french hens",
                      "four calling birds",
                      "five gold rings",
                      "six geese a-laying",
                      "seven swans a-swimming",
                      "eight maids a-milking",
                      "nine ladies dancing",
                      "ten lords a-leaping",
                      "eleven pipers piping",
                      "twelve drummers drumming"]


while 0 < christmasGifts.count {
    // The number of gifts left in christmasGifts
    // will tell us which day we are singing about:
    let day = christmasGifts.count


    // The last gift in the array gets extracted:
    let lastGift = christmasGifts.popLast()


    print(" On the (day) day of Christmas my true love sent to me")
    print("(lastGift!)")
}


// output:

//On the 12 of day Christmas my true love sent to me
//twelve drummers drumming


//On the 11 of day Christmas my true love sent to me
//eleven pipers piping


//On the 10 of day Christmas my true love sent to me
//ten lords a-leaping


// ...

Each iteration of the loop extracts a gift description from the end of the christmasGifts array and prints out the start of the verse that introduces that gift. The loop runs while there are items in the array. In order to be able to modify the size of the christmasGifts array, we need to make it mutable (i.e., define it as a variable rather than a constant). Chapter 19 introduced arrays: have a look if you need more details on how to work with them.

repeat-while

A repeat-whileloop has the following syntax in Swift: repeat { statements } while condition. It first runs the statements inside the curly brackets and then checks if condition is true or false. If it is true, the statements are run again and again until condition evaluates to false. This way the statements in the body of the loop are guaranteed to run at least once, whatever condition evaluates to initially.

Let us rewrite the while loop from the previous example into a repeat-while loop. As you can see in Listing 20-10, the two loops are almost identical. With the repeat-while version it becomes necessary to ensure that there is a string in the array to extract before we use it, because the loop will run once before we get a chance to check if the array had items in it. The if let lastGift = christmasGifts.popLast() statement does that.

Listing 20-10. Printing Out Verses with a repeat-while Loop
repeat {
    // The loop will execute at least once
    // The number of gifts left in christmasGifts
    // will tell us which day we are singing about:
    var day = christmasGifts.count


    // An attempt to extract the last item from the christmasGifts array.
    // If we have already run out of items,
    // the code in the if statement's body won't execute.
    if let lastGift = christmasGifts.popLast(){
        print(" On the (day) of Christmas my true love sent to me")
        let verseLine =
                composeVerseLine(day, gift: lastGift, needsPrefix: false)
        print("(verseLine)")
    }


// the loop repeats until there are no items left in the array
} while christmasGifts.count > 0


// output:
//On the 12 of Christmas my true love sent to me
//twelve drummers drumming,


//On the 11 of Christmas my true love sent to me
//eleven pipers piping,


//On the 10 of Christmas my true love sent to me
//ten lords a-leaping,


//...    

Now, just for fun, we could combine a repeat-while and a while loop to print out the complete verses of the song. Listing 20-11 uses the repeat-while loop we just put together and nests inside it a while loop, which counts down the remaining items in the array (without removing them) and prints out the gifts for the days preceding the current one. As a result, the song gets printed out, but starting from the last verse and continuing to the first one.

Listing 20-11. A Nested Pair of repeat-while and while Loops, Which Print the Song Verses Backward
repeat // The loop will execute at least once {
    // The number of gifts left in christmasGifts
    // will tell us which day we are singing about:
    var day = christmasGifts.count


    // An attempt to extract the last item from the christmasGifts array.
    // If we have already run out of items,
    // the code in the if statement's body won't execute.
    if let lastGift = christmasGifts.popLast()
    {
        print(" On the (day) day of Christmas my true love sent to me")
        let verseLine =
                composeVerseLine(day, gift: lastGift, needsPrefix: false)
        print("(verseLine)")


        // Now count down the previous days
        // and list the accumulated gifts.
        // Note that the prefix – operator
        // decrements day before its value is checked.
        while --day > 0
        {
            let verseLine =
                        composeVerseLine(day, gift: christmasGifts[day - 1])
            print("(verseLine)")
        }
    }


// The loop repeats until there are no items left in the array.
} while christmasGifts.count > 0


// output:

//On the 12 day of Christmas my true love sent to me
//twelve drummers drumming,
//eleven pipers piping,
//ten lords a-leaping,
//nine ladies dancing,
//eight maids a-milking,
//seven swans a-swimming,
//six geese a-laying,
//five gold rings,
//four calling birds,
//three french hens,
//two turtle doves
//and a partridge in a pear tree.


//On the 11 day of Christmas my true love sent to me
//eleven pipers piping,
//ten lords a-leaping,
//...


//...

//On the 1 of Christmas my true love sent to me
//a partridge in a pear tree.

Conditional Statements

Time to talk about choice. You have several conditional statements at your disposal: if, which helps you make a choice based on a condition of type Bool, guard to ensure certain conditions are met before execution can proceed, and switch, which takes care of the more complicated decisions.

if

You have already met with the if statement on many occasions in Swift. The last one was in Listing 20-11 where we checked whether an item could be extracted from the array of Christmas gift descriptions. Here it is again in Listing 20-12:

Listing 20-12. An if Statement, Which Does Optional Binding
// The last gift in the array gets extracted:
if let lastGift = christmasGifts.popLast() {
   // ...
}

Following are a few more differences between if statements in ActionScript and in Swift, which are worth noting:

  • You can’t use anything else but a Bool literal or an expression that evaluates to Bool as the condition of an if statement. Numbers, for example, will not be automatically cast to Bool, so a line like this will not compile: if 1 {}. Similarly, checking if a variable contains nil needs to be explicit. Listing 20-13 demonstrates that the first if statement in it generates a compiler error: optional type 'Int?' cannot be used as a boolean; test for '!= nil' instead .

Listing 20-13. Checking If a Variable or a Constant Is Nil in an if Statement Needs to Be Explicit
var intVar: Int?

// This line will not compile:
if intVar { /*...*/ }


// But this line will:
if nil != intVar { /*...*/ }


// And so will this line, which uses optional binding:
if let _ = intVar { /*...*/ }
Tip

intVar in the example above has been declared as an optional. You can check if an optional instance contains a value or nil by doing if let _ = intVar—this will evaluate to true if intVar is not nil. More on optionals in Chapter 19.

  • The condition after the if statement you see in Listing 20-12 does what is called optional binding: let lastGift = christmasGifts.popLast().

    This simple one-liner does quite a lot of work: it declares the temporary constant lastGift, extracts the last element of the christmasGifts array and assigns it to lastGift. This temporary constant is inferred to be of type Optional with two possible values: an instance of whatever type the christmasGifts array holds (String in this case) or nil. The whole line evaluates to false if lastGift contains nil and to true if it holds a String instance. Put simpler: the body of the if statement will be executed only if lastGift is not nil and indeed contains the last element of the christmasGifts array.

    The last line in Listing 20-13, if let _ = intVar, also uses optional binding but omits the assignment step by providing an undeerscore instead of declaring a temporary constant: you can use this when you only care whether an optional instance contains a value but do not need to know what the value is.

  • Optional binding is the only case, in which you can use the assignment operator (=) as part of the condition in an if statement. An if statement’s condition is expected to evaluate to Bool and, as we saw in Chapter 18 , the assignment operator (=) in Swift does not return a Bool result.

Tip

You can read more on optional binding in Chapter 19.

guard

The guard statement makes sure that a given condition is met before execution can proceed. Its syntax is as follows:

guard booleanCondition else { /* Transfer control elsewhere */ }

Functionally guard works the same way as an if-else statement. It is however more concise than if-else and documents your intentions better in cases where control flow should be transferred elsewhere—out of a loop or back to the caller of a function—unless a condition is met. Note that, unlike if, guard always requires an else clause.

Let us see how we could use guard. In Listing 20-10 we used an if statement with conditional binding in order to extract the last item from the christmasGifts array and use it to compose a song line like this:

if let lastGift = christmasGifts.popLast(){/* Compose and print song line... */}

In Listing 20-14 we replace this with a guard statement. It checks if there are items in the array and if the array is empty, breaks out of the repeat-while loop.

Listing 20-14. Using a guard Statement to Check Conditions
guard christmasGifts.count > 0 else {
    break
}


// The next lines will only be executed if christmasGifts.count is not zero:
let lastGift = christmasGifts.popLast()
// Compose and print song line...

The Mightier Switch

You are already familiar with the concept of a switch statement from ActionScript: it lets you check an expression against a number of discreet values and choose a course of action, depending on whether the expression matches one of these values. The switch statement in Swift uses the same principle but might also surprise you with how much more powerful and foolproof it is. We will go through its superpowers one by one.

Superpower 1: It Won’t Let You Miss a Case

The clauses in a switch statement in Swift must cover all possible scenarios. Depending on the type you are switching on, you have two choices for how to achieve this. You can provide case clauses that cover every value the type might take: this may make sense for types that have a finite set of values, like enums, for example (more on enums in Chapter 22 ). Or, if the type doesn’t allow that, you must provide a default clause, which would handle any value not explicitly covered by a case clause.

The example in Listing 20-15 uses a switch statement to print the name of the month, given a number. Its case statements cover the numbers from 1 to 12 and its default statement deals with any other input.

Listing 20-15. A switch Statement in Swift Must Be Exhaustive
let month = 3

switch month {
    case 1: print("January")
    case 2: print("February")
    case 3: print("March")
    case 4: print("April")
    case 5: print("May")
    case 6: print("June")
    case 7: print("July")
    case 8: print("August")
    case 9: print("September")
    case 10: print("October")
    case 11: print("November")
    case 12: print("December")


    default: print("Can't match month name to (month)")
}


// output: March

The last example shows you the syntax of a basic switch statement. What you might notice as a contrast to ActionScript syntax is:

  • If you don’t add the default clause at the end, this code won’t compile. The compiler issues an error: Switch must be exhaustive, consider adding a default clause. Brilliantly foolproof.

    An example of making a switch statement exhaustive without the need for a default clause would be using enumerations. An enumeration defines a finite set of what you can think of as named constants, so when you use them in the case clauses of a switch statement, the compiler will make sure that you either have a case for every possible value of the enumeration or that you include a default clause instead. You can see examples of that in Chapter 22 , where we delve into enumerations in detail.

  • You don’t need parentheses around the expression after the switch statement. By now you are probably not surprised by this typical Swift syntax.

  • There are no break clauses—more on that in the next section.

Superpower 2: It Won’t Let You Fall Through by Mistake

So, why are those breaks missing? We will explain by contrasting case clauses in ActionScript and in Swift.

In Swift a case clause will not implicitly fall through to the next clause whether you provide a break or not. In fact, you need to explicitly state it if you want fallthrough behavior by using the keyword fallthrough. In addition, you can provide multiple matches in a case clause: you do that by separating them with commas.

Listing 20-16 uses a switch statement, which takes a month and prints out the seasons it spans in some parts of the Northern hemisphere. You can see how several of its case statements use multiple matches: for example, input of either 1 (January) or 2 (February) will result in “winter” being printed out. You can also see the use of the fallthrough keyword, which causes an input of 3 (March) to result in “spans winter and spring”.

Listing 20-16. Special Syntax for Providing Multiple Matches
let month = 3

switch month {
    case 1, 2:      print("winter")
    case 3:         print("spans winter and")
                    fallthrough


    case 4, 5:      print("spring")
    case 6, 7, 8:   print("summer")
    case 9:         print("spans summer and")
                    fallthrough


    case 10, 11:    print("autumn")
    case 12:        print("spans autumn and winter")


    default: print("Hmm, not sure about month (month)...
                        Which calendar did you have in mind?")
}


// output:

//spans winter and
//spring

Superpower 3: You Can Switch Between Ranges of Values

The previous example can be made even more concise with another superpower of Swift’s switch statement: matching ranges. In place of case 6, 7, 8: it is perfectly acceptable to put case 6...8:, using the closed range operator (Listing 20-17).

Listing 20-17. Range Matching
let month = 7

switch month {
    case 1...2:   print("winter")
    case 3:       print("spans winter and"); fallthrough
    case 4...5:   print("spring")
    case 6...8:   print("summer")
    case 9:       print("spans summer and"); fallthrough
    case 10...11: print("autumn")
    case 12:      print("spans autumn and winter")


    default: print("Hmm, not sure about month (month)...
                        Which calendar did you have in mind?")
}


// output: summer

Note how this time we put the fallthrough keyword on the same line as the print statement and separated the two with a semicolon. As we mentioned in Chapter 17 , you can use semicolons at the end of statements in Swift but are not required to, unless you need to separate statements on the same line.

Tip

The closed range operator a...b defines a range of values between a and b, including a and b. You can read about it in more detail in Chapter 18.

Superpower 4: You Can Have Overlapping Case Statements

Swift will also let your case statements overlap. Admittedly it’s debatable whether this is more of an Achilles’s heel or a superpower in earnest, as you can easily shoot yourself in the foot: when you provide overlapping values or ranges of values in your case statements, the first one found to be a match is the one that is executed.

Listing 20-18 modifies the last example by allowing the ranges to overlap, so for an input of 3 or 9 you have two matching case statements each. It’s important to note that we still need the fallthrough keyword, in order to have an input of 3 print out “spans winter and spring,” otherwise only the body of the first matching case will be executed resulting in “spans winter and.”

Listing 20-18. Overlapping Case Statements
let month = 3

switch month {
    case 1...2:   print("winter")


    // Note that we still need the fallthrough keyword,
    // inspite of the overlapping cases:
    case 3:       print("spans winter and"); fallthrough
    case 3...5:   print("spring")
    case 6...8:   print("summer")


    // Note that we still need the fallthrough keyword,
    // inspite of the overlapping cases:
    case 9:       print("spans summer and"); fallthrough
    case 9...11:  print("autumn")
    case 12:      print("spans autumn and winter")


    default: print("Hmm, not sure about month (month)...
                        Which calendar did you have in mind?")
}


// output:

//spans winter and
//spring

Superpower 5: You Can Switch Between Different Types of Values

Swift doesn’t limit you to only matching integer values in your switch statements. The next three examples showcase switch statements that use Double, String and Tuple values.

The first example in Listing 20-19 defines a range, which helps round a double number up or down to its nearest integer. Note that the range this time is defined by the open range operator a..<b.

Listing 20-19. Matching Double Values
let doubleNumber = 17.5
let fraction = doubleNumber - Double(Int(doubleNumber))


switch fraction {
    case 0.0..<0.5: print("The nearest integer is (Int(doubleNumber))")
    default:        print("The nearest integer is (Int(doubleNumber) + 1)")
}


// output: The nearest integer is 18
Tip

The open range operator a..<b defines a range of values between a and b, including a, but not b. You can find out more in Chapter 18.

Listing 20-20 uses a string as criteria for switching:

Listing 20-20. String Matching
let monthName = "April"

switch monthName {
    case "December", "January", "February":     print("winter")
    case "March", "April", "May":               print("spring")
    case "June", "July", "August":              print("summer")
    case "September", "October", "November":    print("autumn")


    default: print("Can't mstch a season to (monthName)")
}


// output: spring

The next example in Listing 20-21 is a bit more elaborate. It starts with defining an enumeration for the days of the week (see Chapter 22 for details on enumerations). For the purposes of this example you can think of an enum as providing a set of named values, where WeekDay.Monday has a value of 1, WeekDay.Tuesday has a value of 2, and so on. The timeAndDay constant is a tuple (a type, which holds two or more values together), which has a time and a day for shopping. The switch statement that follows checks the time and the day and decides whether these fall inside the local stores’ opening times: 9 a.m. to 5 p.m. Monday to Saturday. Each case statement checks two values: the time and the day.

Listing 20-21. Tuples
// An enumeration of week days (see Chapter 22 for details on enums)
enum WeekDay : Int {
    case Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}


let timeAndDay = (13, WeekDay.Saturday)

// Check if the stores are open at the given time
switch timeAndDay {
    case (_, WeekDay.Sunday): print("The stores are closed all day on Sunday.")
    case (9...17, _): print("The stores are open.")


    default: print("The stores are closed.")
}


// output: The stores are open.
Tip

Enumerations are shown off in their glory in Chapter 22 and you can read more on tuples in Chapter 19.

You have probably noticed some weirdness in the syntax of the case statements above in the lurking underscores. This leads us to another superpower . . .

Superpower 6: Using Any Value

Putting an underscore in place of one of the values inside a case clause, as shown in Listing 20-21, is construed as “any value.” So, for example, case (_, WeekDay.Sunday) should be read as “any time on Sunday” and case (9...17, _) as “Between 9 a.m. and 5 p.m. on any day of the week.” The switch statement in the Listing 20-21 first checks if the day in the time tuple is Sunday. If it is, then it ignores the time and prints out “The stores are closed all day on Sunday.” If time is on a different day, then the switch doesn’t care which day it is: as long as the time is between 9 a.m. and 5 p.m., the stores are opened. The default clause takes care of the values not covered by the two case clauses: when the day is between Monday and Saturday and the time—outside the 9 a.m.- 5 p.m. interval.

Superpower 7: Value Binding

Value binding allows you to assign values to temporary variables or constants in the case clauses, in order to access these values. Listing 20-22 shows a modification of the switch statement in Listing 20-21. The first case clause in it defines a temporary constant called time and assigns the first element of the timeAndDay tuple to it. The value of time is then passed to the print function.

Listing 20-22. Value Binding
switch timeAndDay {
    // Create a temporary constant, called time
    // and assign the first element of the tuple to it:
    case (let time, WeekDay.Sunday):
        print("The stores are closed on Sunday at (time).")


    case (9...17, _): print("The stores are open.")

    default: print("The stores are closed")
}


// output: The stores are open.

Superpower 8: You Can Provide Nuance with where Clauses

We are getting to the end of the list of superpowers. This last one, however, is extra special. You can make the checks in the case clauses even more elaborate by adding conditions to them, using a where clause. In this last modification of the store opening times example, shown in Listing 20-23, the last case clause is a different way of expressing “any day of the week between 9 a.m. and 5 p.m.” with a where clause (given we have already filtered Sunday out). It also defines two temporary constants and binds timeAndDay’s two values to them.

Listing 20-23. Where Clauses
switch timeAndDay {
    // Create a temporary constant, called time
    // and assign the first element of the tuple to it:
    case (let time, WeekDay.Sunday):
        print("The store is closed on Sunday at (time)")


    case let (time, dayOfWeek) where time >= 9 && time <= 17:
        print("The store is open on (dayOfWeek) at (time)")


    default: print("The store is closed")
}

Jumping Around: Control Transfer

We will finish this chapter with a few words on control transfer statements, all of which you have encountered so far either by using their ActionScript counterparts or when you did the previous examples in this chapter.

continue

As in ActionScript, you use continue to interrupt the current iteration of a loop and to start the next one.

break

You can use break to stop the execution of a loop or to exit out of a case in a switch statement. As we saw earlier when we were delving into the superpowers of switch, break statements are optional.

fallthrough

This is your new friend when you work with switch statements. Instead of making sure you don’t forget to put break at the end of each case, omit all the breaks, and use fallthrough when you intend execution to continue into the next case or default clause. See Listing 20-16 in the section “Superpower 2” for an example implementation.

return

As you would expect, return transfers the control out of the current function or method. Nothing to add to what you already know from your ActionScript experience. I, however, have a little something for you: just as you thought I had forgotten my promise to polish The Twelve Days of Christmas example . . . Listing 20-24 shows a function that will help us print out the day names with their proper suffixes: it uses a simple switch statement, which abruptly interrupts the execution of the function and returns a result as soon as it finds a match.

Listing 20-24. Using return
func getNumberSuffix(number : Int) -> String {
    switch number {
        case 11...13: return "th"


        default:
            switch number % 10 {
                case 1: return "st"
                case 2: return "nd"
                case 3: return "rd"


                default: return "th"
            }
    }
}

Labels

When you have nested loops or switch statements, you can use labels in order to distinguish them. A label is a name that you come up with, followed by a colon that you put at the start of your loop or switch statement. Then, when you use the break and continue statements, you can be explicit about which loop or switch you want to continue or break out of.

The final example in this chapter completes the mission of printing out the lyrics of The Twelve Days of Christmas. It uses the function getNumberSuffix we defined in Listing 20-24 and prints out the names of the days as ordinal numbers.

In order to demonstrate the use of labels, I have allowed myself a perversion. See if you can spot it in Listing 20-25.

Listing 20-25. Using Labels in Loops
// Label the outer loop:
outerLoop: for day in 1...christmasDays {
    print(" On the (day)(getNumberSuffix(day))
        day of Christmas my true love sent to me")


    var previousDay = day

    // Label the inner loop:
    innerLoop: while true // Don't do this at home! {
        if --previousDay < 0
        {
            // Transfer control back to the for loop
            // and continue with its next iteration:
            continue outerLoop
        }


        let verseLine =
                composeVerseLine(previousDay,
                                    gift: christmasGifts[previousDay],
                                    needsPrefix: day > 1)
        print("(verseLine)")
    }
}

Did you see my misdemeanor? I made the inner while loop infinite, in order to show you how to use labels. When the loop’s condition (--previousDay < 0) evaluates to true, we call continue outerLoop, which transfers control to the next iteration of the outer for loop. At last, this code outputs the song lyrics almost as we would expect to see them:

On the 1st day of Christmas my true love sent to me
a partridge in a pear tree,


On the 2nd day of Christmas my true love sent to me
and two turtle doves.
a partridge in a pear tree,


On the 3rd day of Christmas my true love sent to me
three french hens
and two turtle doves.
a partridge in a pear tree,


On the 4th day of Christmas...

. . . almost, as you would normally expect to see the days of Christmas spelled out as “first,” “second,” and so on, instead of “1st,” “2nd,” and so on. Let me guess . . . You are reading this in June, aren’t you?

Summary

This chapter gave you the tools for understanding and controlling the flow of execution in your code. We saw how loops work and especially how they might surprise you if you are coming from an ActionScript background. The different flavors of the for and while loops almost look and feel the same as their ActionScript counterparts, but they hide some subtle differences. We also uncovered the superpowers of Swift’s switch statement: from its safety mechanisms to its versatility with different types and ways of defining conditions.

With this much ground covered, we are ready to move on to object-oriented programming topics. I’ll meet you at the next chapter.

Footnotes

1 Speaking of menagerie, you might like Frank Kelly’s version of the text. Go on, look it up on YouTube, you know you want to.

2 Integers, as well as all the other primitive types in Swift, are implemented as structures behind the scenes and thus can have properties and methods. You can read about structures in Chapter 21 .

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset