Swift Tutorial Part 3: Flow Control
Welcome to part 3 of our Swift tutorial, where you’ll learn how code decisions using Booleans and repeat tasks using loops to control the flow. By Lorenzo Boaro.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Swift Tutorial Part 3: Flow Control
35 mins
- Getting Started
- Boolean Operators
- Boolean Logic
- String Equality
- The if Statement
- Encapsulating Variables
- The Ternary Conditional Operator
- Loops
- While Loops
- Repeat-while Loops
- Breaking Out of a Loop
- Advanced Control Flow
- Ranges
- For Loops
- Continue Statement
- Switch Statements
- Advanced Switch Statements
- Partial Matching
- Where to Go From Here?
Switch Statements
Another way to control flow is through the use of a switch
statement, which lets you execute different bits of code depending on the value of a variable or constant.
Here’s a very simple switch
statement that acts on an integer:
let number = 10
switch number {
case 0:
print("Zero")
default:
print("Non-zero")
}
The code will print the following:
The purpose of this switch
statement is to determine whether or not a number is zero.
To handle a specific case, you use case
, followed by the value that you want to check for, which, in this case, is 0
. Then, you use default
to signify what should happen for all other values.
Here’s another example:
switch number {
case 10:
print("It's ten!")
default:
break
}
This time you check for 10, in which case, you print a message. Nothing should happen for other values. When you want nothing to happen for a case, or you want the default state to run, you use the break
statement. This tells Swift that you meant to not write any code here and that nothing should happen. Cases can never be empty, so you must write some code, even if it’s just a break
!
switch
statements work with any data type! Here’s an example of switching on a string:
let string = "Dog"
switch string {
case "Cat", "Dog":
print("Animal is a house pet.")
default:
print("Animal is not a house pet.")
}
This will print the following:
In this example, you provide two values for the case, meaning that if the value is equal to either "Cat"
or "Dog"
then the statement will execute the case.
Advanced Switch Statements
You can also give your switch
statements more than one case. In the previous section, you saw an if
statement using multiple else-if
statements to convert an hour of the day to a string describing that part of the day. You could rewrite that more succinctly with a switch
statement, like so:
let hourOfDay = 12
var timeOfDay = ""
switch hourOfDay {
case 0, 1, 2, 3, 4, 5:
timeOfDay = "Early morning"
case 6, 7, 8, 9, 10, 11:
timeOfDay = "Morning"
case 12, 13, 14, 15, 16:
timeOfDay = "Afternoon"
case 17, 18, 19:
timeOfDay = "Evening"
case 20, 21, 22, 23:
timeOfDay = "Late evening"
default:
timeOfDay = "INVALID HOUR!"
}
print(timeOfDay)
This code will print the following:
Remember ranges? Well, you can use ranges to simplify this switch
statement. You can rewrite it in a more succinct and clearer way using ranges as shown below:
var timeOfDay2 = ""
switch hourOfDay {
case 0...5:
timeOfDay2 = "Early morning"
case 6...11:
timeOfDay2 = "Morning"
case 12...16:
timeOfDay2 = "Afternoon"
case 17...19:
timeOfDay2 = "Evening"
case 20..<24:
timeOfDay2 = "Late evening"
default:
timeOfDay2 = "INVALID HOUR!"
}
print(timeOfDay2)
It’s also possible to match a case to a condition based on a property of the value. As you learned in the first part of this tutorial series, you can use the modulo operator to determine if an integer is even or odd. Consider this code:
switch number {
case let x where x % 2 == 0:
print("Even")
default:
print("Odd")
}
This will print the following:
This switch
statement uses the let-where
syntax, meaning the case will match only when a certain condition is true
. The let
part binds a value to a name, while the where
part provides a Boolean condition that must be true
for the case to match. In this example, you’ve designed the case to match if the value is even — that is, if the value modulo 2 equals 0.
The method by which you can match values based on conditions is known as pattern matching.
In the previous example, the binding introduced an unnecessary constant x
; it’s simply another name for number
. You are allowed to use number
in the where
clause and replace the binding with an underscore to ignore it:
switch number {
case _ where number % 2 == 0:
print("Even")
default:
print("Odd")
}
Partial Matching
Another way you can use switch
statements with matching to great effect is as follows:
let coordinates = (x: 3, y: 2, z: 5)
switch coordinates {
case (0, 0, 0): // 1
print("Origin")
case (_, 0, 0): // 2
print("On the x-axis.")
case (0, _, 0): // 3
print("On the y-axis.")
case (0, 0, _): // 4
print("On the z-axis.")
default: // 5
print("Somewhere in space")
}
This switch
statement makes use of partial matching. Here’s what each case does, in order:
-
Matches precisely the case in which the value is
(0, 0, 0)
. This is the origin of 3D space. - Matches y=0, z=0 and any value of x. This means the coordinate is on the x-axis.
- Matches x=0, z=0 and any value of y. This means the coordinate is on the y-axis.
- Matches x=0, y=0 and any value of z. This means the coordinate is on the z-axis.
- Matches the remainder of coordinates.
You’re using the underscore to mean that you don’t care about the value. If you don’t want to ignore the value, then you can bind it and use it in your switch
statement, like this:
switch coordinates {
case (0, 0, 0):
print("Origin")
case (let x, 0, 0):
print("On the x-axis at x = \(x)")
case (0, let y, 0):
print("On the y-axis at y = \(y)")
case (0, 0, let z):
print("On the z-axis at z = \(z)")
case let (x, y, z):
print("Somewhere in space at x = \(x), y = \(y), z = \(z)")
}
Here, the axis cases use the let
syntax to pull out the pertinent values. The code then prints the values using string interpolation to build the string.
Notice how you don’t need a default in this switch
statement. This is because the final case is essentially the default; it matches anything, because there are no constraints on any part of the tuple. If the switch
statement exhausts all possible values with its cases, then no default is necessary.
Also notice how you could use a single let
to bind all values of the tuple: let (x, y, z)
is the same as (let x, let y, let z)
.
Finally, you can use the same let-where
syntax that you saw earlier to match more complex cases. For example:
switch coordinates {
case let (x, y, _) where y == x:
print("Along the y = x line.")
case let (x, y, _) where y == x * x:
print("Along the y = x^2 line.")
default:
break
}
Here, you match the “y equals x” and “y equals x squared” lines.