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,
switch
checks the value offruit
. - When it matches “Apple”, it executes the first
print
statement and then exits the switch statement. - There’s no need for a
break
after 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
guard
statement is used for optional binding and early exit. It checks if the optionalname
contains a value. let name = name
attempts to unwrap the optionalname
. Ifname
is notnil
, it assigns the unwrapped value to a new constant (also conveniently namedname
but could be named differently), which is available in the remaining part of the function’s scope.- The
else
block executes if the optionalname
isnil
. Inside this block, the function prints “No name provided” and then usesreturn
to 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
else
block 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: Error
declares a new enumeration type namedVendingMachineError
that conforms to theError
protocol. This is a way of defining custom error types in Swift.case outOfStock
is a case of theVendingMachineError
enum, representing a specific kind of error where an item is out of stock in the vending machine.func vend(itemNamed name: String) throws
defines a function namedvend
that takes aString
parameter and is marked withthrows
. This indicates that the function can throw an error.throw VendingMachineError.outOfStock
inside the function, an error is thrown using thethrow
keyword. This error is theoutOfStock
case of theVendingMachineError
enum. When this line is executed, the function immediately stops executing further code and propagates the error to be handled by its caller.- The
do
block is used to handle errors thrown by functions marked withthrows
. try vend(itemNamed: "Candy Bar")
calls thevend
function and is prefixed withtry
, indicating that this function call might throw an error. The function is called with the argument"Candy Bar"
.- If the
vend
function throws an error (in this case, it always does), the execution immediately moves to thecatch
block. - The
catch
block 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 thedo
block.
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
searchForNumber
takes an array of integers as its input. - It iterates over each number in the array using a
for-in
loop. - 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
defer
block is used to schedule a block of code that runs just before the function exits. - The code inside the
defer
block (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 areturn
statement elsewhere in the function. - When
processFile
is called, the first thing it does is set up thedefer
block. However, the code inside thedefer
block is not executed immediately. It’s merely scheduled to run later. - The function then prints “Processing file.”
- As the function reaches its end, the
defer
block 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!