100 Days of SwiftUI Checkpoint 3

This blog post's content is based on the fantastic learning materials from Paul Hudson's 100 Days of SwiftUI course, available for free at Hacking with Swift.
Control Flow in Swift
Conditions and loops are the building blocks that allow your code to make decisions and repeat actions, turning simple instructions into dynamic programs.
Conditional Statements
if
,else if
, andelse
: These allow you to execute code based on whether a condition istrue
orfalse
. You can use a simpleif
, anif
with anelse
, or multipleelse if
clauses for complex decision-making.- Combining Conditions:
||
(OR): If either of two conditions istrue
, the entire condition istrue
.&&
(AND): If both conditions aretrue
, the entire condition istrue
.
switch
Statements: Offer a cleaner way to handle multiple possible states for a single value, especially with enums. Swift ensures yourswitch
is exhaustive, often requiring adefault
case for types like strings or integers. Thefallthrough
keyword allows execution to continue to the next case, but it's rarely used.
Ternary Conditional Operator
- Syntax:
condition ? valueIfTrue : valueIfFalse
. This concise operator is a shorthand for anif-else
statement that returns a value. - Purpose: While it can be hard to read initially, it's very commonly used in contexts like SwiftUI where traditional
if-else
statements can't be directly embedded. Think of it as checking What's your condition, True result, False result (WTF).
Loops
for-in
Loops: Ideal for iterating over finite sets of data like arrays, dictionaries, sets, or ranges. You can assign each item to a loop variable to use inside the loop body, or use an underscore (_
) if you don't need the variable itself.while
Loops: Perfect for repeating a block of code until a condition becomesfalse
. You provide any condition, and the loop will continue to execute as long as that condition remainstrue
.- Controlling Loop Flow:
continue
: Skips the rest of the current iteration of the loop and moves to the next one.break
: Exits the entire loop immediately, continuing execution after the loop body.
import UIKit
// MARK: - Conditional Statements (if/else)
// This section demonstrates how to use 'if' statements to execute code
// based on whether a condition is true or false.
var someCondition = true
let math = 5 + 5
// An 'if' statement executes its block if the condition is true.
if someCondition {
print("This code is executed when someCondition is true")
print(math)
}
let score = 85
// Checking if a score is greater than a threshold.
if score > 84 {
print("You did well!")
}
let speed = 88
let percentage = 85
let age = 18
// Using comparison operators (>=, <).
if speed >= 88 {
print("Where we're going, we don't need roads.")
}
// An 'if-else' statement provides an alternative block to execute
// if the initial 'if' condition is false.
if percentage < 85 {
print("You need to study more.")
} else {
print("Great! You passed.")
}
if age >= 16 {
print("You can drive.")
}
let ourName = "Dave"
let friendName = "Will"
// String comparison (lexicographical order).
// 'D' comes before 'W' in the alphabet, so "Dave" is considered "less than" "Will".
if ourName < friendName {
print("It's \(ourName) vs \(friendName)")
}
if ourName > friendName {
print("It's \(friendName) vs \(ourName)")
}
var numbers = [1, 2, 3]
numbers.append(4)
// Conditional modification of an array.
if numbers.count > 3 {
numbers.remove(at: 0)
}
print(numbers)
let country = "Canada"
// Checking for equality using '=='.
if country == "United States" {
print("Merica")
}
let name = "Taylor Swift"
// Checking for inequality using '!='.
if name != "Madonna" {
print("Welcome \(name)")
}
// Demonstrating different ways to check if a string is empty.
var username = "taylorswift13"
// Method 1: Checking against an empty string literal.
if username == "" {
username = "Anonymous"
}
print("Welcome \(username)")
var username1 = "topgun13"
// Method 2: Checking the character count.
if username1.count == 0 {
username1 = "Anonymous"
}
print("Welcome \(username1)")
var username2 = "voltron13"
// Method 3: Using the 'isEmpty' property (most idiomatic Swift).
if username2.isEmpty == true { // Can also be written as 'if username2.isEmpty'
username2 = "Anonymous"
}
print("Welcome \(username2)")
// MARK: - Switch Statements
// Switch statements provide a cleaner way to handle multiple possible states
// for a single value, especially with enums.
enum Weather {
case sun, rain, wind, snow, unknown
}
let forecast = Weather.snow
// A 'switch' statement evaluates 'forecast' and executes the code block
// for the matching 'case'.
switch forecast {
case .sun:
print("It should be a nice day.")
case .rain:
print("Pack an umbrella.")
case .wind:
print("Wear something warm")
case .snow:
print("School is cancelled.")
case .unknown:
print("Our forecast generator is broken!")
}
let place = "Metropolis"
// 'default' case is required if all possible cases are not explicitly handled.
switch place {
case "Gotham":
print("You're Batman!")
case "Mega-City One":
print ("You're Judge Dredd")
case "Wakanda":
print("You're Black Panther!")
default:
print("Who are you?")
}
let day = 5
print("On the first day of Christmas my my true love (Rachel) gave to me")
// 'fallthrough' allows execution to continue into the next case block
// after a match is found. Use with caution as it can make code less readable.
switch day {
case 5:
print("5 golden rings")
fallthrough
case 4:
print("4 calling birds")
fallthrough
case 3:
print("3 French hens")
fallthrough
case 2:
print("2 turtle doves")
fallthrough
default:
print("and a partridge in a pear tree")
}
// MARK: - Ternary Conditional Operator
/*
The ternary conditional operator provides a concise way to choose between two values
based on a condition. It's often used in contexts like SwiftUI where 'if/else'
statements cannot be directly embedded within certain expressions.
Syntax: condition ? valueIfTrue : valueIfFalse
- '?' can be read as "then"
- ':' can be read as "otherwise"
*/
let age1 = 18
// If age1 >= 18 is true, canVote is "Yes"; otherwise, it's "No".
let canVote = age1 >= 18 ? "Yes" : "No"
print(canVote)
let hour = 23
print(hour < 12 ? "It's before noon." : "It's after noon.")
let names = ["James", "Kaylee", "Mal"]
// Using ternary for conditional string formatting.
let crewCount = names.isEmpty ? "No one" : "\(names.count) people"
print(crewCount)
enum Theme {
case light, dark
}
let theme = Theme.light
// Ternary operator for assigning a background color based on theme.
let background = theme == .dark ? "black" : "white"
print(background)
// MARK: - Loops
// This section covers different types of loops for repeating work.
// MARK: For-In Loops
// 'for-in' loops iterate over sequences, such as arrays or ranges.
let platforms = ["iOS", "macOS", "tvOS", "watchOS"]
for os in platforms {
// 'os' is a loop constant, automatically created and accessible
// only within the loop's curly braces.
print("Swift works great on, \(os).")
}
// Iterating through a closed range (inclusive of both start and end values).
for i in 1...12 {
print("5 x \(i) is \(5 * i)")
}
// Nested 'for-in' loops for creating multiplication tables.
for i in 1...5 {
print("The \(i) times table.")
for j in 1...10 {
print(" \(i) x \(j) is \(i * j)")
}
print() // Prints an empty line for readability between tables.
}
// Demonstrating closed range (1...5) vs. half-open range (1..<5).
for i in 1...5 {
print("Counting from 1 through 5: \(i)") // Includes 5
}
for i in 1..<5 {
print("Counting from 1 up to 5: \(i)") // Excludes 5
}
var lyric = "Haters gonna"
// Using '_' as a wildcard when the loop variable itself is not needed.
for _ in 1...3 {
lyric += " hate!"
}
print(lyric)
// MARK: While Loops
// 'while' loops repeat a block of code as long as a condition is true.
var countdown = 10
while countdown > 0 {
print("\(countdown)...")
countdown -= 1 // Decrementing the counter to eventually make the condition false.
}
print("Blastoff!")
let id = Int.random(in: 1...1000)
let amount = Double.random(in: 0...1)
var rool = 0
// Loop continues until 'rool' is exactly 20.
while rool != 20 {
rool = Int.random(in: 1...20)
print("I rolled a \(rool)")
}
print("Critical Hit!")
// MARK: - Controlling Loop Flow (break and continue)
// 'continue' and 'break' allow for fine-grained control over loop execution.
let filenames = ["me.jpg", "work.txt", "sophie.jpg", "ironman.mp4"]
// 'continue' skips the rest of the current loop iteration and moves to the next.
// Here, it skips files that don't end with "jpg".
for image in filenames {
if image.hasSuffix("jpg") == false {
continue
}
print("Found an image: \(image)")
}
let number1 = 4
let number2 = 14
var multiples = [Int]()
// 'break' exits the loop entirely.
// Here, the loop stops once 10 multiples are found.
for i in 1...100_000 {
if i.isMultiple(of: number1) && i.isMultiple(of: number2) {
multiples.append(i)
if multiples.count == 10 {
break // Exit the loop as soon as 10 multiples are collected.
}
}
}
print(multiples)
//---- Checkpoint 3 Fizz Buzz
for i in 1...100 {
// Order of operations matters!
// The most specific condition (multiples of both 3 and 5)
// must be checked first, or it will never be reached.
if i.isMultiple(of: 3) && i.isMultiple(of: 5) {
print("\(i) FizzBuzz")
}
else if i.isMultiple(of: 3) {
print("\(i) Fizz")
}
else if i.isMultiple(of: 5) {
print("\(i) Buzz")
}
else {
print(i)
}
}