Swift: Swift Conditionals
Conditionals let your program react differently to different situations, just like a traffic light changes signals based on traffic. This lesson covers all conditional control mechanisms in Swift: if-else, switch, and more.
1. What You'll Learn
- Using if / else if / else for branching logic
- Using switch for multi-value matching and pattern matching
- Using range operators
...and..<to simplify range conditions - Using fallthrough for switch case fall-through
- Using the where clause to add extra constraints to conditions
2. A True Story: A Backend Developer
(1) The Pain Point: Multi-Layer Role-Based Permissions Turned Code into Spaghetti
Bob is building a user permission system at a SaaS company. The system has 5 user roles (admin / editor / viewer / guest / banned), each with different access levels to over 20 API endpoints. Bob initially used 15 layers of nested if-else:
if role == "admin" {
if action == "delete" {
// allow
} else if action == "edit" {
// allow
}
} else if role == "editor" {
// 700 lines of repeated code...
}
The code quickly ballooned to over 700 lines. Adding a new role meant modifying 5 different places. Bob spent a full week fixing a security vulnerability caused by incorrect if-else ordering.
(2) The Solution: switch
Bob refactored the permission system using switch statements:
let role = "editor"
switch role {
case "admin":
print("Full access granted")
case "editor":
print("Read and write access")
case "viewer", "guest":
print("Read-only access")
case "banned":
print("Access denied")
default:
print("Unknown role")
}
(3) The Result: Code Shrank 80%, Logic Became Crystal Clear
| Dimension | 15-Layer if-else | After switch Refactor |
|---|---|---|
| Lines of code | 700+ | 150 |
| Time to add a new role | 30 minutes | 3 minutes |
| Logic errors | 3 per month | 0 per month |
| Readability score | 3/10 | 9/10 |
3. if/else Conditional Statements
if/else is Swift's most fundamental conditional control structure. It decides which code block to execute based on a Bool value.
graph TB
A[Condition] -->|true| B[if block]
A -->|false| C[else if / else block]
B --> D[Continue]
C --> D
| Syntax | Description | Example |
|---|---|---|
| if condition { } | Execute when condition is true | if score >= 60 { } |
| if ... else { } | Execute else when condition is false | if ... else { } |
| if ... else if ... else { } | Check multiple conditions in order | if ... else if ... else { } |
(1) Basic if and else
let temperature = 30
if temperature > 25 {
print("It's hot outside")
} else {
print("It's cool outside")
}
(2) Multiple Conditions with else if
let score = 85
if score >= 90 {
print("Grade: A")
} else if score >= 80 {
print("Grade: B")
} else if score >= 70 {
print("Grade: C")
} else if score >= 60 {
print("Grade: D")
} else {
print("Grade: F")
}
▶ Example: Login Status Check
// ============================================
// Display different messages based on login status
// ============================================
let isLoggedIn = true
let hasProfile = false
if isLoggedIn {
print("Welcome back!")
if hasProfile {
print("Your profile is complete")
} else {
print("Please complete your profile")
}
} else {
print("Please log in first")
}
Output:
TEXT 📖 Display onlyWelcome back! Please complete your profile
4. switch Multi-Branch Matching
switch is a more powerful multi-branch matching tool than if-else. Swift's switch does not require break—execution automatically exits after a match.
graph TB
A[Value] --> B[case 1]
A --> C[case 2]
A --> D[case 3]
A --> E[default]
B --> F[Execute and Exit]
C --> F
D --> F
E --> F
| Feature | Swift switch | C / Java switch |
|---|---|---|
| Implicit break | Automatic (no break needed) | Must write break |
| Range matching | Supports ... and ..< |
Not supported |
| Compound matching | Comma-separated values | Relies on fallthrough |
| Exhaustive | Must cover all possibilities | Not enforced |
| Default branch | Uses default | Uses default |
(1) Basic switch Syntax
let fruit = "apple"
switch fruit {
case "apple":
print("It's an apple")
case "banana":
print("It's a banana")
case "orange":
print("It's an orange")
default:
print("Unknown fruit")
}
(2) Range Matching and Compound Matching
let age = 25
switch age {
case 0..<13:
print("Child")
case 13..<20:
print("Teenager")
case 20..<65:
print("Adult")
case 65...:
print("Senior")
default:
print("Invalid age")
}
▶ Example: HTTP Status Code Handling
// ============================================
// Handle HTTP response status codes with switch
// ============================================
let statusCode = 404
switch statusCode {
case 100..<200:
print("Informational")
case 200..<300:
print("Success")
case 300..<400:
print("Redirection")
case 400..<500:
print("Client error")
if statusCode == 404 {
print("Resource not found")
}
case 500..<600:
print("Server error")
default:
print("Unknown status code")
}
Output:
TEXT 📖 Display onlyClient error Resource not found
5. Advanced Control: fallthrough, where, and the Ternary Operator
Swift provides additional tools to make conditional logic more flexible.
| Tool | Purpose | Example |
|---|---|---|
| fallthrough | Fall through to the next case in switch | case "a": fallthrough |
| where | Add extra filtering to a condition | case let x where x > 10: |
| Ternary ? : | Concise either-or choice | let max = a > b ? a : b |
(1) fallthrough
let number = 2
switch number {
case 1:
print("One")
case 2:
print("Two")
fallthrough
case 3:
print("Three or fell through from two")
default:
print("Other")
}
(2) where Condition Filtering
let point = (x: 3, y: 4)
switch point {
case let (x, y) where x == y:
print("On the diagonal")
case let (x, y) where x > y:
print("X is larger")
case let (x, y) where x < y:
print("Y is larger")
default:
print("On an axis")
}
(3) The Ternary Conditional Operator
let isMember = true
let discount = isMember ? 0.2 : 0.0
print("Discount: \(discount * 100)%")
▶ Example: Order Discount Calculator
// ============================================
// Combine if/switch/ternary to calculate order discounts
// ============================================
let orderTotal = 250.0
let customerTier = "gold"
// Ternary operator: base discount
let baseDiscount = orderTotal > 100 ? 0.05 : 0.0
// switch: membership tier discount
let tierDiscount: Double
switch customerTier {
case "platinum":
tierDiscount = 0.20
case "gold":
tierDiscount = 0.15
case "silver":
tierDiscount = 0.10
default:
tierDiscount = 0.0
}
// if: cap the combined discount
let totalDiscount = baseDiscount + tierDiscount
let finalDiscount = totalDiscount > 0.3 ? 0.3 : totalDiscount
let finalPrice = orderTotal * (1 - finalDiscount)
print("Order total: $\(orderTotal)")
print("Tier: \(customerTier)")
print("Discount: \(Int(finalDiscount * 100))%")
print("Final price: $\(finalPrice)")
Output:
TEXT 📖 Display onlyOrder total: $250.0 Tier: gold Discount: 20% Final price: $200.0
6. Full Example: User Permission Management System
// ============================================
// User permission management system
// Integrates if/switch/where/ternary operators
// ============================================
import Foundation
enum UserRole {
case admin, editor, viewer, guest, banned
}
enum ActionResult {
case granted, denied(String)
}
func checkPermission(role: UserRole, action: String, isOwner: Bool) -> ActionResult {
switch role {
case .banned:
return .denied("Account is banned")
case .admin:
return .granted
case .editor:
if action == "delete" && !isOwner {
return .denied("Only owners can delete")
}
return .granted
case .viewer:
switch (action, isOwner) {
case (_, false):
return .denied("Viewers cannot modify content")
case ("read", true):
return .granted
default:
return .denied("Unknown action")
}
case .guest:
return action == "read" ? .granted : .denied("Guests can only read")
}
}
let testCases = [
(UserRole.admin, "delete", false),
(UserRole.editor, "delete", true),
(UserRole.editor, "delete", false),
(UserRole.viewer, "read", true),
(UserRole.viewer, "write", false),
(UserRole.guest, "read", false),
(UserRole.banned, "read", false)
]
for (role, action, isOwner) in testCases {
let result = checkPermission(role: role, action: action, isOwner: isOwner)
switch result {
case .granted:
print("[GRANTED] \(role) can \(action)")
case .denied(let reason):
print("[DENIED] \(role) cannot \(action) -- \(reason)")
}
}
Output:
TEXT 📖 Display only[GRANTED] admin can delete [GRANTED] editor can delete [DENIED] editor cannot delete -- Only owners can delete [GRANTED] viewer can read [DENIED] viewer cannot write -- Viewers cannot modify content [GRANTED] guest can read [DENIED] banned cannot read -- Account is banned
❓ FAQ
if for 2-3 branches. Use switch when you have more than 3 branches or need range/pattern matching. switch enforces exhaustive handling of all possibilities, making it safer than if.... and ..<?a...b includes both a and b (closed range). a..<b includes a but not b (half-open range). For example, 1...3 includes 1, 2, 3; 1..<3 includes 1, 2.if instead—a long one-liner becomes harder to read.📖 Summary
- if/else is the most fundamental conditional control, best for 2-3 branches
- switch is best for 3+ branches and supports range matching, compound matching, and value binding
- switch's fallthrough allows fall-through to the next case, useful for sequential matching scenarios
- The where clause adds extra filtering conditions to switch cases and for loops
- The ternary operator ? : is best for concise either-or assignments
- Swift's switch requires exhaustive handling, enhancing code safety
📝 Exercises
- Beginner: Use if/else to write a body temperature classifier: temp < 36.0 outputs "Low", 36.0...37.5 outputs "Normal", > 37.5 outputs "Fever".
- Intermediate: Refactor the beginner exercise using switch to also support temp < 35.0 outputting "Dangerously Low". Use range matching syntax.
- Challenge: Create a payment fee calculator. Fee rules: Credit card 2.5% (≥$100: 2.5% - 0.5%), Debit card 1.0% (capped at $5), PayPal 3.0% + $0.30. Implement with switch + where.