Control flow
Control flow, also known as flow of control, refers to the order in which statements, instructions, or functions are executed within an application. Swift supports all of the familiar control flow statements that are in C-like languages. These include loops (that is, for
, while
, and do/while
), conditional statements (that is, if
and switch
) and the transfer of control statements (that is, break
and continue
). In addition to the standard C control flow statements, Swift has also added additional statements, such as the for-in
loop, and has enhanced some of the existing statements, such as the switch
statement.
Let's begin by looking at conditional statements in Swift.
Conditional statements
A conditional statement will check a condition and execute a block of code only if the condition is met. Swift provides both the if
and if-else
conditional statements. Let's take a look at how to use the if
and if-else
conditional statements to execute blocks of code, only if a specified condition is met.
The if statement
The if
statement will check the conditional statement and if it is true, it will execute the block of code. The if
statement takes the following format:
if condition { block of code }
Now, let's look at how to use the if
statement:
let teamOneScore = 7 let teamTwoScore = 6 if teamOneScore > teamTwoScore { println("Team One Won") }
In the preceding example, we begin by setting the teamOneScore
and teamTwoScore
variables. We then use the if
statement to check if the value of teamOneScore
is greater than the value of teamTwoScore
. If the value is greater, we print Team One Won
to the console. If we run this code, we will indeed see that Team One Won
is printed to the console, but if the value of teamTwoScore
were greater than the value of teamOneScore
, then nothing would be printed to the console. That would not be the best way to write an application, because we would want the user to know which team actually won. The if-else
statement can help us with this problem.
Executing codes with the if-else statement
The if-else
statement will check the conditional statement and if it is true, it will execute a block of code. If the conditional statement is not true, then it will execute a separate block of code. The if-else
statement follows this format:
if condition { block of code if true } else { block of code if not true }
Let's modify the preceding example to tell the user which team won:
var teamOneScore = 7 var teamTwoScore = 6 if teamOneScore > teamTwoScore { println("Team One Won") } else { println("Team Two Won") }
This new version will print out Team One Won
, if the value of teamOneScore
is greater than the value of teamTwoScore
; otherwise, it will print out the message, Team Two Won
. What do you think the code will do if the value of teamOneScore
were equal to the value of teamTwoScore
? In the real world, we will have a tie, but in the preceding code, we will print out Team Two Won
; this would not be fair to team one. In cases like this, we can use multiple else if
and plain else
statements, as shown in the following example:
var teamOneScore = 7 var teamTwoScore = 6 if teamOneScore > teamTwoScore { println("Team One Won") } else if teamTwoScore > teamOneScore { println("Team Two Won") } else { println("We have a tie") }
In the preceding code, if the value of teamOneScore
is greater than the value of teamTwoScore
, we print Team One Won
to the console. We then have another if
statement that checks to see whether the value of teamTwoScore
is greater than the value of teamOneScore
, but this if
statement follows an else
statement, which means the if
statement is checked only if the previous conditional statement is false. Finally, if both the if
statements were false, then we assume that the values are equal and print We have a tie
to the console.
A conditional statement checks the condition once, and if the condition is met, it executes the block of code. What if we wanted to continuously execute the block of code until a condition is met? For this, we would use one of the looping statements that are in Swift. Let's take a look at looping statements in Swift.
The for loops
The for
loop variants are probably the most widely used looping statements. Swift offers the standard C-based for
loop and also an extra for-in
loop. The standard C-based for
loop executes a block of code until a condition is met, usually by incrementing or decrementing a counter. The for-in
statement will execute a block of code for each item in a range, collection, or sequence. We usually use one of the for
loop variants when we need to iterate over a collection, or have a set number of times we want to execute a block of code.
Using the for loop variant
Let's begin by looking at the standard C-based for
loop and how we would use it. The format for the for
statement looks like this:
for initialization; condition; update-rule { block of code }
As shown in the preceding format, the for
loop has three sections:
- Initialization: This is where we initialize any variables needed; this can contain multiple initializations, separated by commas, if needed
- Condition: This is the condition to check; when the condition is false, the loop will exit
- Update-rule: This is the what needs to be updated at the end of each loop
It is important to understand the order in which the sections are called. When the execution of the code encounters a for
loop, the initialization section of the for
loop is called to initialize the variables. Next, the condition section is executed to verify whether the block of code should be executed, and, if so, it will execute the block of code. Finally, the update-rule is called to perform any updates before looping back and starting over.
The following example shows how to use the for
loop to go through a range of numbers:
for var index = 1; index <= 4; index++ { println(index) }
In the preceding example, the index
variable is initialized to the number 1
. At the beginning of each loop, we check whether the index
variable is equal to or less than number 4
. If the index
variable is equal to or less than number 4
, the block of code is executed (which prints the index
variable to the console). Finally, we increment the index
variable before looping back and starting over. Once the index
variable is greater than 4
, the for
loop exits. If we run the preceding example, the numbers 1
through 4
will indeed be printed to the console.
One of the most common uses of a for
loop is to iterate through a collection and perform a block of code for each item in that collection. Let's look at how to loop through an array, followed by an example of how to loop through a dictionary:
var countries = ["USA","UK", "IN"] for var index = 0; index < countries.count; index++ { println(countries[index]) }
In the preceding example, we begin by initializing the countries
array with the abbreviations of three countries. In the for
loop, we initialize the index
variable to 0
(the first index of the array), and in the condition statement of the for
loop, we check whether the index variable is less than the number of elements in the countries
array. Each time we loop, we retrieve and print the value from the countries
array at the index specified by the index
variable.
One of the biggest mistakes that new programmers make when they use a for
loop to iterate through an array, is to use the less than or equal to (<=) operator, rather than the less than (<) operator. Using a less than or equal to (<=) operator would cause one, too many iterations through the loop and generate an Index out of Bounds
exception when the code is run. In the preceding example, a less than or equal to operator will generate a count from 0 through 3 inclusively because there are three elements in the array; however, the elements in the array have indexes from 0 through 2 (0, 1, and 2). So, when we try to retrieve the value at index 3, the Index out of Bounds
exception will be thrown.
Let's look at how we would iterate through a dictionary with a standard C-based for
loop:
var dic = ["USA": "United States", "UK": "United Kingdom", "IN":"India"] var keys = dic.keys.array for var index = 0; index < keys.count; index++ { println(dic[keys[index]]) }
In the preceding example, we begin by creating a dictionary object that contains country names as the values with their abbreviations as the keys. We then use the keys
property of the dictionary to get an array of keys. In the for
loop, we initialize the index
variable to 0
, verify whether the index
variable is less than the number of elements in the countries array and then increments the index
variable at the end of each loop. Each time we loop, we print the country's name to the console.
Now, let's look at how to use the for-in
statement and how it can help prevent common mistakes that occur when we use the standard for
statement.
Using the for-in loop variant
In the standard for
loop, we provide an index and then loop until a condition is met. While this approach is very good when we want to loop through a range of numbers, it can cause bugs, as mentioned earlier, if our condition statements are not correct. The for-in
loop is designed to prevent these types of exceptions.
The for-in
loop iterates over a collection of items or a range of numbers and executes a block of code for each item in the collection or range. The format for the for-in
statement looks like this:
for variable in Collection/Range { block of code }
As we can see in the preceding code, the for-in
loop has two sections:
- Variable: This variable will change each time the
for-in
loop executes and will hold the current item from the collection or range - Collection/Range: This is the collection or range to iterate through
Let's look at how to use the for-in
loop to iterate through a range of numbers:
for index in 1...5 { println(index) }
In the preceding example, we iterate over a range of numbers from 1
to 5
and print each of the numbers to the console. This particular for-in
statement uses the close range operator (…
) to give the for-in
loop a range to go through. Swift also provides a second range operation called the half-open range operator (..<
). The half-open range operator iterates through the range of numbers but does not include the last number. Let's look at how to use the half-range operator:
for index in 1..<5 { println(index) }
In the closed range operator example (…
), we will see the numbers 1
though 5
printed to the console. In the half-range operator example, the last number (5
) will be excluded; therefore, we will see the numbers 1
though 4
printed to the console.
Now, let's see how to iterate over an array with the for-in
loop:
var countries = ["USA","UK", "IN"] for item in countries { println(item) }
In the preceding example, we iterate through the countries
array and print each element of the counties
array to the console. As we can see, iterating though an array with the for-in
loop is safer, cleaner, and a lot easier than using the standard C-based for
loop.
Let's look at how to iterate over a dictionary with the for-in
loop:
var dic = ["USA": "United States", "UK": "United Kingdom", "IN":"India"] for (abbr, name) in dic { println("\(abbr) -- \(name)") }
In the preceding example, we used the for-in
loop to iterate through each key-value pair of a dictionary. Each item in the dictionary is returned as a (key,value) tuple. We can decompose (key,value) tuple members as named constants within the body of the for-in
loop. One thing to note is that since a dictionary does not guarantee the order that items are stored in, the order that they are iterated over may not be the same as the order they were inserted in.
Now, let's look at another type of loop, the while
loop.
The while loop
The while
loop executes a block of code until a condition is met. Swift provides two forms of while
loops, these are the while
and do-while
loops. We use while
loops when the number of iterations to perform is not known and is usually dependent on some business logic. A while
loop is used when you want to run a loop zero or more times, while a do-while
loop is used when you want to run the loop one or more times.
Using the while loop
The while
loop starts by evaluating a conditional statement and then repeatedly executes a block of code while the conditional statement is true. The format for the while
statement is as follows:
while condition { block of code }
Let's look at how to use a while
loop. In the following example, the while
loop will continue to loop while a randomly generated number is less than 4
. In this example, we are using the arc4random()
function to generate a random number between 0
and 4
.
var ran = 0 while ran < 4 { ran = Int(arc4random() % 5) }
In the preceding example, we begin by initializing the ran
variable to 0
. The while
loop then checks the ran
variable, and if its value is less than 4
, a new random number, between 0
and 4
, is generated. The while
loop will continue to loop while the randomly generated number is less than 4
. Once the randomly generated number is equal to or greater than 4
, the while
loop will exit.
In the preceding example, the while
loop checks the conditional statement prior to generating a new random number. What if we did not want to check the conditional statement prior to generating a random number? We could generate a random number when we initialize the ran
variable, but that means we would need to duplicate the code that generates the random numbers. That would not be an ideal solution. It would be preferable to use the do-while
loop for such instances.
Using the do-while loop
The difference between the while
and do-while
loops is that, while
loops check the conditional statement prior to executing the block of code in the loop block, that is, all variables in the conditional statements need to be initialized prior to executing the while
loop. The do-while
loop will run through the loop block prior to checking the conditional statement for the first time; this means that we can initialize the variables in the conditional block of code. Use of the do-while
loop is preferred when the conditional statement is dependent on the code in the loop block. The do-while
loop takes the following format:
do { block of code } while condition
Let's take a look at this specific example by creating a do-while
loop where we initialize the variable we are checking, in the conditional statement, within the loop block:
var ran: Int do { ran = Int(arc4random() % 5) } while ran < 4
In the preceding example, we define the ran
variable as an Int
, but we do not initialize it until we enter the loop block and generate a random number. If we try to do this with the while
loop (leaving the ran
variable uninitialized), we will receive a Variable used before being initialized
exception.
The switch statement
The switch
statement takes a value and then compares it to several possible matches, and executes the appropriate block of code based on the first successful match. The switch
statement is an alternative to using the if
statement when there could be several possible matches. The switch
statement takes the following format:
switch value { case match1 : block of code case match2 : block of code …… as many cases as needed default : block of code }
Unlike the switch
statements in most other languages, in Swift, it does not fall through to the next case
statement; therefore, we do not need to use a break
statement to prevent the fall through. This is another safety feature that is built into Swift, since one of the most common programming mistakes, with the switch
statement, made by beginner programmers is to forget the break
statement at the end of the case
statement. Let's look at how to use the switch
statement:
var speed = 300000000 switch speed { case 300000000: println("Speed of light") case 340: println("Speed of sound") default: println("Unknown speed") }
In the preceding example, the switch
statement takes the value of the speed
variable and compares it to the two case
statements, and if the value of speed matches either case, it will print out what the speed is. If the switch
statement does not find a match, it will print out the unknown speed
message.
Every switch
statement must have a match for all possible values. This means that unless we are matching against an enum, each switch
statement must have a default
case. Let's look at a case where we do not have a default
case:
var num = 5 switch num { case 1 : println("number is one") case 2 : println("Number is two") case 3 : println("Number is three") }
If we put the preceding code into a Playground and attempt to execute it, we will receive an switch must be exhaustive, consider adding a default clause
error. This is a compile time error; therefore, we will not be notified until we attempt to execute the code.
It is possible to include multiple items in a single case. To set multiple items within a single case, we would need to separate the items with a comma. Let's look at how we would use the switch
statement to tell us if a character was a vowel or a consonant:
var char : Character = "e" switch char { case "a", "e", "i", "o", "u": println("letter is a vowel") case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": println("letter is a consonant") default: println("unknown letter") }
We can see in the preceding example that each case has its multiple items. Commas separate these items and the switch
statement will attempt to match the char
variable to each item listed in the case
statement.
It is also possible to check the value of a switch
statement to see if it is included in a range. To do this, we would use a range operator in the case
statement, as you can see in the following example:
var grade = 93 switch grade { case 90...100: println("Grade is an A") case 80...89: println("Grade is a B") case 70...79: println("Grade is an C") case 60...69: println("Grade is a D") case 0...59: println("Grade is a F") default: println("Unknown Grade") }
In the preceding example, the switch
statement takes the grade
variable and compares it with the grade
ranges in each case
statement, and prints out the appropriate grade.
In Swift, any case
statement can contain an optional guard expression that can provide an additional condition to validate. The guard expression is defined with the where
keyword. Let's say, in our preceding example, we had students who were receiving special assistance in the class and we wanted to define a grade of D
for them in the range of 55 to 69. The following example shows how to do this:
var studentId = 4 var grade = 57 switch grade { case 90...100: println("Grade is an A") case 80...89: println("Grade is a B") case 70...79: println("Grade is an C") case 55...69 where studentId == 4: println("Grade is a D for student 4") case 60...69: println("Grade is a D") case 0...59: println("Grade is a F") default: println("Unknown Grade") }
One thing to keep in mind with the guard expression is that Swift will attempt to match the value starting with the first case statement and working its way down checking each case statement in order. This means, if we put the case
statement with the guard expression after the Grade F case
statement, then the case
statement with the guard expression would never be reached. The following example illustrates this:
var studentId = 4 var grade = 57 switch grade { case 90...100: println("Grade is an A") case 80...89: println("Grade is a B") case 70...79: println("Grade is an C") case 60...69: println("Grade is a D") case 0...59: println("Grade is a F") //The following case statement would never be reached because the //grades would always match one of the previous two case 55...69 where studentId == 4: println("Grade is a D for student 4") default: println("Unknown Grade") }
Note
A good rule of thumb is that if you are using guard expressions, always put the case
statements with the guard expression before any similar case
statements without guard expressions. Now, let's look at control transfer statements.
Control transfer statements
Control transfer statements are used to transfer control to another part of the code. Swift offers four control transfer statements; these are continue
, break
, fallthrough
, and return
, and then look at the return
statement when we discuss Functions later in this chapter.
The continue statement
The continue
statement tells a loop to stop executing the code block and go to the next iteration of the loop. The following example shows how to use a continue
statement to print out only the odd numbers in a range:
for i in 1...10 {{{ if i % 2 == 0 { continue } println("\(i) is odd") }
In the preceding example, we loop through a range of 1
through 10
. For each iteration of the for-in
loop, we use the remainder (%
) operator to see if the number is odd or even. If the number is even, the continue
statement tells the loop to immediately go to the next iteration of the loop. If the number is odd, we print out the number is odd and then move ahead. The output of the preceding code is as follows:
1 is odd 3 is odd 5 is odd 7 is odd 9 is odd
Now, let's look at the break
statement.
The break statement
The break
statement immediately ends the execution of a code block within the control flow. The following example shows how to break out of a for
loop when we encounter the first even number:
for i in 1...10 { if i % 2 == 0 { break } println("\(i) is odd") }
In the preceding example, we loop through the range of 1
through 10
. For each iteration of the for
loop, we use the remainder (%
) operator to see if the number is odd or even. If the number is even, we use the break
statement to immediately exit the loop. If the number is odd, we print out that the number is odd and then go to the next iteration of the loop. The preceding code has the following output:
1 is odd
The fallthrough statement
In Swift, switch
statements do not fall through like other languages; however, we can use the fallthrough
statement to force them to fall through. The fallthrough
statement can be very dangerous because once a match is found; then, the next case defaults to true and that code block is executed. The following example illustrates this:
var name = "Jon" var sport = "Baseball" switch sport { case "Baseball": println("\(name) plays Baseball") fallthrough case "Basketball": println("\(name) plays Basketball") fallthrough default: println("Unknown sport") }
In the preceding example, since the first case, Baseball
, matches the code and the remaining code blocks also execute, the output looks like this:
Jon plays Baseball Jon plays Basketball Unknown sport
Now that we have seen how the control flow statements work in Swift, let's give an introduction to functions and classes in Swift.