if, guard & Loops
So far every program ran from the first line to the last. Real programs make decisions ("if the marks are above 33, print Pass") and repeat work ("for every student in the class, print a report card"). Statements that change the order in which code runs are called control flow.
In this lesson you will learn Swift's decision makers, if, guard and a first look at switch, and its loops: for-in, while and repeat-while. You will also learn break and continue, and how Swift's guard keeps functions tidy.
if, else if and else
An if statement runs a block only when its condition is true. Add else if for more conditions and else for "everything else". The condition must be a real Bool; Swift does not treat 0 or an empty string as false. The braces are always required, even for one line.
let marks = 76
if marks >= 90 {
print("Grade A+")
} else if marks >= 75 {
print("Grade A")
} else if marks >= 33 {
print("Pass")
} else {
print("Fail")
}Grade A
Swift checks the conditions from top to bottom and runs only the first block whose condition is true. Since 76 >= 90 is false and 76 >= 75 is true, it prints "Grade A" and skips the rest.
if and switch as expressions
Since Swift 5.9, if and switch can also produce a value, so you can assign their result directly. Each branch must give a value of the same type.
let temperature = 41
let advice = if temperature >= 40 {
"Stay indoors"
} else if temperature >= 30 {
"Carry water"
} else {
"Enjoy the weather"
}
print(advice)
let hour = 14
let greeting = switch hour {
case 5..<12: "Good morning"
case 12..<17: "Good afternoon"
default: "Good evening"
}
print(greeting)Stay indoors Good afternoon
A switch compares one value against several patterns, here ranges of hours. It must be exhaustive: every possible value must match some case, which is why there is a default. Unlike C and Java, Swift's switch does not fall through to the next case, so there is no break to forget. You will use switch much more in Enums & switch.
guard: exit early
guard checks a condition that must be true for the rest of the code to make sense. If the condition is false, the else block runs and must leave the current scope, with return in a function or continue/break in a loop. You will learn functions properly in the next section; for now just notice the shape.
func bookTicket(age: Int, seatsLeft: Int) {
guard age >= 5 else {
print("Children under 5 travel free")
return
}
guard seatsLeft > 0 else {
print("Sorry, the train is full")
return
}
print("Ticket booked for age \(age)")
}
bookTicket(age: 3, seatsLeft: 10)
bookTicket(age: 30, seatsLeft: 0)
bookTicket(age: 30, seatsLeft: 4)Children under 5 travel free Sorry, the train is full Ticket booked for age 30
With guard, the error cases are handled at the top and the "happy path" stays at the left edge, not buried inside nested if blocks. The compiler checks that every guard else block really exits. guard let also unwraps optionals, which you will use a lot in Optionals & Unwrapping.
for-in loops
A for-in loop runs once for each item in a sequence: a range, an array, a dictionary or a string. Use stride to count in steps, where to skip items, and _ when you do not need the loop variable.
for n in 1...3 {
print("7 x \(n) = \(7 * n)")
}
let years = Array(stride(from: 2020, through: 2026, by: 2))
print(years)
var multiplesOfThree: [Int] = []
for n in 1...10 where n.isMultiple(of: 3) {
multiplesOfThree.append(n)
}
print(multiplesOfThree)
var stars = ""
for _ in 1...5 {
stars += "*"
}
print(stars)7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 [2020, 2022, 2024, 2026] [3, 6, 9] *****
stride(from:through:by:) includes the end value; stride(from:to:by:) stops before it. A negative step counts down: stride(from: 10, through: 0, by: -5) gives 10, 5, 0. To count down by one, you can also write for n in (1...5).reversed().
while and repeat-while
A while loop checks its condition before each run, so it may run zero times. A repeat-while loop checks after each run, so it always runs at least once. Use them when you do not know in advance how many times to repeat.
var savings = 0
var week = 0
while savings < 1000 {
week += 1
savings += 150
}
print("Week \(week): ₹\(savings)")
var attempts = 0
repeat {
attempts += 1
print("Sending OTP, attempt \(attempts)")
} while attempts < 3Week 7: ₹1050 Sending OTP, attempt 1 Sending OTP, attempt 2 Sending OTP, attempt 3
Priya saves ₹150 a week. After 6 weeks she has ₹900, still below 1000, so the loop runs a seventh time and stops at ₹1050. Always make sure something inside a while loop moves it towards its end, or it will run forever.
break, continue and labels
continue skips the rest of the current pass and moves to the next item. break leaves the loop completely. With nested loops, give the outer loop a label and write break label to leave both at once.
let orders = [250, -1, 400, 0, 999, 120]
var total = 0
for amount in orders {
if amount <= 0 { continue } // skip invalid entries
if amount > 900 { break } // stop at a suspicious order
total += amount
}
print(total)
let shelves = [["Maths", "Hindi"], ["Physics", "Atlas", "Biology"], ["Atlas"]]
search: for (index, books) in shelves.enumerated() {
for book in books where book == "Atlas" {
print("Found Atlas on shelf \(index + 1)")
break search
}
}650 Found Atlas on shelf 2
The first loop adds 250 and 400, skips -1 and 0, and stops at 999, so 120 is never added. In the second, break search ends both loops as soon as the first atlas is found, so shelf 3 is never checked.
Common mistakes
- Using a number as a condition.
if count { }does not compile; writeif count > 0. - A
guardthat does not exit. Theelseblock mustreturn,break,continueorthrow. - Off-by-one loops.
0...array.countgoes one past the end; use0..<array.countorarray.indices. - Endless
whileloops. Change the variable the condition depends on inside the loop.
Key points
if,else ifandelsechoose a branch; conditions must beBool, and braces are required.ifandswitchcan be expressions that produce a value (Swift 5.9 and later).guard condition else { exit }handles bad cases early and keeps the main path flat.for-inloops over ranges and collections;stridesteps,wherefilters and_ignores the value.whilechecks first;repeat-whilealways runs at least once.continueskips one pass,breakends a loop, and labels let you break out of nested loops.
Exercise
Print the bus fare for passengers aged 2, 8, 35, 64 and 70. Fares: under 5 free, 5 to 11 half fare, 60 and above a 40 percent senior discount, everyone else full fare of ₹200. Use a for-in loop and an if expression to choose each fare, and keep a running total. Skip any age below 0 with continue.
Show solution
let ages = [2, 8, 35, 64, 70]
var total = 0
for age in ages {
if age < 0 { continue }
let fare = if age < 5 {
0
} else if age < 12 {
100
} else if age >= 60 {
120
} else {
200
}
total += fare
print("Age \(age): ₹\(fare)")
}
print("Total: ₹\(total)")Age 2: ₹0 Age 8: ₹100 Age 35: ₹200 Age 64: ₹120 Age 70: ₹120 Total: ₹540
Each branch of the if expression gives an Int, so fare is an Int. The senior fare is 200 minus 40 percent, which is 120.
Quick Quiz
1. What happens if a guard condition is false?
guard requires its else block to leave the scope with return, break, continue or throw.
2. How many times does repeat { } while false run its body?
repeat-while checks the condition after each pass, so it always runs at least once.
3. Which loop prints 10, 8, 6?
through: includes the end value; to: would stop before 6, and 10...6 is an invalid range.
4. Does a Swift switch case fall through to the next case automatically?
Swift cases never fall through implicitly; fallthrough exists but is rarely needed.
Learn Swift with a mentor
Free lessons get you started. Our Mobile App Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
