In SwiftUI development, a common question arises: Should you use structs or classes for your…
Swift Control Flow Statements

In this post, we’re diving into the world of Swift control flow statements. From simple if statements to the more complex guard and, we’ll explore these essential tools with playful and practical examples.
Swift Control Flow Statements Essentials
Control flow statements in Swift guide the execution of your code. Let’s break them down with examples you can try in a Swift playground.
if and if-else Statements Statements
Used for basic conditional operations.
let age = 18
if age >= 18 {
print("You are an adult.")
} else {
print("You are a minor.")
}
if as an Expression:
let category = if age >= 18 {
"Adult"
} else {
"Minor"
}
print(category) // Output would be "Adult"
Switch Statement
Swift’s switch statement doesn’t require a break statement in each case as it does in many other languages. In Swift, the switch case automatically exits after the case is executed, unless you explicitly tell it to fall through to the next case.
let fruit = "Apple"
switch fruit {
case "Apple":
print("It's an apple.")
case "Banana":
print("It's a banana.")
default:
print("It's some other fruit.")
}
- In this example,
switchchecks the value offruit. - When it matches “Apple”, it executes the first
printstatement and then exits the switch statement. - There’s no need for a
breakafter each case.
switch as an Expression
let color = switch fruit {
case "Apple":
"Red"
case "Banana":
"Yellow"
default:
"Unknown"
}
print(color) // Output would be "Red"
for-in Loop
Perfect for iterating over collections like arrays or ranges.
for number in 1...5 {
print("Number is \(number)")
}
while Loop
Runs a block of code as long as a condition is true.
var count = 5
while count > 0 {
print(count)
count -= 1
}
repeat-while Loop Statement
Like a while loop, but the condition is at the end.
repeat {
print("This will run at least once.")
} while false
guard Statement
Used for early exits in a function.
func greet(name: String?) {
guard let name = name else {
print("No name provided")
return
}
print("Hello, \(name)!")
}
greet(name: "Alice")
- The
guardstatement is used for optional binding and early exit. It checks if the optionalnamecontains a value. let name = nameattempts to unwrap the optionalname. Ifnameis notnil, it assigns the unwrapped value to a new constant (also conveniently namednamebut could be named differently), which is available in the remaining part of the function’s scope.- The
elseblock executes if the optionalnameisnil. Inside this block, the function prints “No name provided” and then usesreturnto exit early. This means the function does not proceed to the greeting if no name is provided. - If the optional contains a value, the function skips the
elseblock and continues.
do-catch Block statement
Handles errors in a block of code.
enum VendingMachineError: Error {
case outOfStock
}
func vend(itemNamed name: String) throws {
throw VendingMachineError.outOfStock
}
do {
try vend(itemNamed: "Candy Bar")
} catch {
print("Item not available.")
}
enum VendingMachineError: Errordeclares a new enumeration type namedVendingMachineErrorthat conforms to theErrorprotocol. This is a way of defining custom error types in Swift.case outOfStockis a case of theVendingMachineErrorenum, representing a specific kind of error where an item is out of stock in the vending machine.func vend(itemNamed name: String) throwsdefines a function namedvendthat takes aStringparameter and is marked withthrows. This indicates that the function can throw an error.throw VendingMachineError.outOfStockinside the function, an error is thrown using thethrowkeyword. This error is theoutOfStockcase of theVendingMachineErrorenum. When this line is executed, the function immediately stops executing further code and propagates the error to be handled by its caller.- The
doblock is used to handle errors thrown by functions marked withthrows. try vend(itemNamed: "Candy Bar")calls thevendfunction and is prefixed withtry, indicating that this function call might throw an error. The function is called with the argument"Candy Bar".- If the
vendfunction throws an error (in this case, it always does), the execution immediately moves to thecatchblock. - The
catchblock is where you handle the error. Here, it simply prints the message"Item not available.". This is a generic catch block that catches any error thrown within thedoblock.
break and return statements
break exits a loop, and return exits a function.
Imagine a function that searches through an array of numbers. If it finds the number 3, it uses break to stop the search. If the number 5 is found before number 3, the function immediately returns, indicating the search was unsuccessful.
func searchForNumber(in numbers: [Int]) {
for number in numbers {
if number == 3 {
print("Found number 3, stopping search.")
break // Stop the loop if number 3 is found
} else if number == 5 {
print("Encountered number 5 before finding 3, exiting function.")
return // Exit the function if number 5 is found before 3
}
print("Checking number \(number)")
}
print("Search completed.")
}
searchForNumber(in: [1, 2, 5, 3, 4]) // Test the function with an array
- The function
searchForNumbertakes an array of integers as its input. - It iterates over each number in the array using a
for-inloop. - During each iteration:
- If the current number is 3, it prints a message and executes
break. This stops the loop, and the search ends successfully. - If the current number is 5, it prints a different message and executes
return. This causes the function to exit immediately, even if there are more numbers to check. In this case, the search ends without finding 3. - For any other number, it simply prints that number is being checked.
- If the current number is 3, it prints a message and executes
- After the loop, a final message “Search completed.” is printed, but this will only be reached if neither 3 nor 5 is found in the array.
throw statement
Throws an error for error handling.
func checkTemperature(_ temp: Int) throws {
if temp > 100 {
throw VendingMachineError.outOfStock
}
}
defer statement
Runs code just before exiting a scope
func processFile() {
defer {
print("Closing file.")
}
print("Processing file.")
}
processFile()
- The
deferblock is used to schedule a block of code that runs just before the function exits. - The code inside the
deferblock (print("Closing file.")) is executed regardless of how the function exits. It could be a normal exit at the end of the function or an exit caused by an error or areturnstatement elsewhere in the function. - When
processFileis called, the first thing it does is set up thedeferblock. However, the code inside thedeferblock is not executed immediately. It’s merely scheduled to run later. - The function then prints “Processing file.”
- As the function reaches its end, the
deferblock is executed, printing “Closing file.”
#if, #endif, #available statements
Used for compile-time checks and platform/version-specific code.
#if os(macOS)
print("Running on macOS.")
#else
print("Not running on macOS.")
#endif
if #available(iOS 14, *) {
print("iOS 14 or newer")
} else {
print("Older iOS version")
}
Conclusion
Swift’s control flow statements are like the conductor of an orchestra, guiding the flow of your program’s execution with precision and flexibility. Experiment with these examples in a Swift playground, and watch as your coding skills grow!
