What are basic flow statements? These are several statements which help you to structure the program code in a way that allows you to do different action(s) based on the data stored in particular variables. We will learn how to execute just part of the code if a certain condition is met (the condition could be a pretty complex Boolean expression). Then, we will find a way to execute different actions several times in a loop. The next thing will be to learn how to repeat things until a condition is met and to stop executing statements once the condition is not satisfied. Using flow-control statements, we can construct pretty complex code chunks, similar to what we can express with regular text writing. To develop a program, we should first create an algorithm (a sequence of steps) which leads to the desired result, taking into account all external and internal conditions. Based on this sequence, we can then develop a program, using all flow operators. But let's get familiar with some forms of them.
Basic flow statements
The if statements – how to control the code flow
This is how we can branch our code logic based on some data stored in a variable:
let num = 5
if num % 2 == 0 {
print("The number \(num) is even.")
} else {
print("The number \(num) is odd.")
}
The general pattern of an if statement is organized as follows:
var logicalCheck = 7 > 5
if (logicalCheck) {
//code which will be executed if the logical check is evaluated to true
} else {
//code which will be executed if the logical check is evaluated to false
}
We know that the if clause gives us huge freedom to shape the code that will be executed (evaluated). An application may handle many different cases, but only the code that fulfills the conditions encoded in our solution will be triggered.
Loops
Let's learn how to implement repetitive tasks. There are several ways to do that, using different loops: while, for...in, and repeat...while. The most popular one is the for...in loop. Here is what the basic form looks like:
let collection = [1, 2, 3]
for variable in collection {
//do some action
}
The code will be interpreted like this: the variable will be set to all possible values, which are stored in the collection. If the collection is empty, then no code will be executed. If there are some elements, then the body of the loop (the code in curly braces) will be executed for each element of the collection. The variable loops through every single element and can be used in code.
We need an example to illustrate this. Let's use the following code to print all numbers from 1 to 10, inclusive:
var sum = 0
for index in 1...10 {
sum += index
print("(index)")
}
print("Sum: \(sum)")
//sum is equal to 55
The sum of all numbers from 1 to 10 is stored in a separate variable and the code prints every single number on a new line. The sequence defined with 1...10 is converted to a collection (we can think of it as an array), which is fueling the for...in loop.
Take a look at the following code:
let threeTimes = 3
for _ in 1...threeTimes {
print("Print this message.")
}
Using _ (underscore) we declare that the argument should ignore the values set in the variable, and it doesn't matter to the rest of the code. The code will print three times: Print this message.
The while loops
The while loops execute the body of the loop (list of the statements in the body part) until the condition is evaluated to false.
There are two types of while loops. There is the classical while loop, which checks the condition, and, if it holds, then the code in the body is executed. Then the check is performed again and everything is repeated until the condition is evaluated to false. The other variant is the repeat...while loop, which first executes the body, and then does the check. The second type is executed at least once, compared to the first one, which could be completely skipped:
var i = 1
let max = 10
var sum = 0
while i <= max {
sum += i
i += 1
}
print("Sum: \(sum)")
The code sums all numbers from 1 to 10. The condition will be broken once i reaches 11.
We can use repeat...while to do the same:
var i = 1
let max = 10
var sum = 0
repeat {
sum += i
i += 1
} while i <= max
print("Sum: \(sum)")
We can use while to implement the repeat...while loops and the reverse, but with slight modifications. The best rule for picking the right type of loop is to know whether the sequence should be executed at least once. Executing once means that it's much easier to implement it using repeat...while; otherwise, the classical while loop is the best choice.
There are some special conditions which we should handle, but to do so, let's see what they are.
We can use the special words—continue and break—to trigger special behavior while we are in a loop. The continue statement is used when you want to stop the current iteration of the loop and start over. When using this, be careful that you change the value in the condition; otherwise, the loop could be an infinite one, which means that your program won't end.
The break statement is used once we want to stop the entire loop. Be careful when you have nested loops. The break statement stops the current iteration immediately, and then jumps to the very first line after the end of the innermost loop, which contains the break statement. If you want to break two or more nested loops, then you have to find an appropriate way to do so. To be explicit when breaking nested loops, you may use labeled statements. It is a convenient way to give a name of a loop and then to change the flow when using break. It's good to know that break may be used as part of a switch statement. This will be discussed in the next part.
There are a few other special words, such as return , throw, and fallthrough which change the default order of execution of the code. We will get familiar with these later.
The switch statement
A switch statement is a concise way to describe a situation where we have several possible options to pick from and we don't want to write a lot of boilerplate code using the already familiar if statement.
Here is the general pattern of a switch statement (please note that this is not a valid Swift code):
switch a-variable-to-be-matched {
case value-1:
//code which will be executed, if variable has value-1
//we need at least one valid executable statement here
(comments are not an executable statement)
case value-2,
value-3:
//code which will be executed, if variable has value-2 or value-3
default:
//code which will be executed, if variable has value different
from all listed cases
}
What we see is that switch has many possible cases, each one starting with the special word case, and then a specific value. Swift supports specific value matching, but it supports more complex rules for pattern matching. Each case could be considered as a separate if statement. If one case is activated, then all others are skipped. The default case is a specific one and is triggered if there is no match with any other case. The default case appears at the end, and it's defined with the special word default.
We can use break to interrupt execution of the code in a case statement. If we want to have an empty case statement, it's good to add break.
We have some specifics with the implementation of switch in Swift, which are new when compared to the other programming languages, but they improve the readability of the code. First, there is now a way to have an empty body of a specific case. To be correct, we have to add at least one valid statement after the case. There is no implicit fallthrough after each case. This means that once the last executable statement in a case branch is triggered, we are continuing after the switch statement. Nothing else that is part of the switch statement will be executed. We could consider that every case statement has a hidden break at its very end. Next, we need the special word fallthrough to simulate the regular behavior of the switch. Another interesting thing is that we can have interval matching, tuples matching, and value bindings. Finally, we can use the where clause if we want to express some dependency between the data which should be matched. It's also possible to list several cases if they have to share the code which should be executed. They have to be separated with ,.
Here is code that shows how easy and smart switch is:
let point = (1, 1)
switch point {
case let (x, y) where x == y:
print("X is \(x). Y is \(y). They have the same value.");
case (1, let y):
print("X is 1. Y is \(y). They could be different.");
case (let x, 1):
print("X is \(x). Y is 1. They could be different.");
case let (x, y) where x > y:
print("X is \(x). Y is \(y). X is greater than Y.");
default:
print("Are you sure?")
}