An infinite loop in Swift is a loop that never stops executing on its own. That might sound like a bug — and often it is — but sometimes it’s exactly what you want. In fact, the entire engine that keeps an iOS app alive and responsive is built on a controlled infinite loop. Understanding what infinite loops are, when they’re useful, and how to avoid the accidental ones is a fundamental skill for every Swift developer.
In this article, you’ll learn what an infinite loop is, how to write one intentionally in Swift, why they sometimes appear by accident, and how to catch them before they ruin your app. You’ll also see how this concept shows up in real iOS code in ways you probably didn’t expect.
The Basic Syntax
The simplest way to write an infinite loop in Swift is with a while true statement. Here’s what that looks like:
var count = 0
while true {
count += 1
print("Count is \(count)")
if count == 5 {
break
}
}Let’s walk through what each part does:
| Line | What it does |
|---|---|
var count = 0 | Sets up a counter variable. We’ll use this to track how many times the loop has run. |
while true { } | Creates a loop that runs forever. The condition true is always true, so the loop never naturally stops on its own. |
count += 1 | Increments the counter by 1 on every pass through the loop. |
print("Count is \(count)") | Prints the current count to the console. String interpolation with \(count) inserts the value of the variable into the string. |
if count == 5 { break } | Once the count reaches 5, the break keyword exits the loop immediately. Without this, the loop would run forever. |
This example is technically an infinite loop that we’ve chosen to exit manually. That’s a completely valid pattern in Swift — and you’ll see it in real code.
Breaking It Down
The key thing to understand about an infinite loop is that the condition never becomes false on its own. Normally, a while loop checks a condition at the start of each iteration. When the condition is false, the loop ends. When you write while true, that condition is always true, so the loop will never stop unless you explicitly tell it to.
There are two keywords that let you control a loop from the inside:
- break — exits the loop immediately. The code after the loop continues running.
- continue — skips the rest of the current iteration and jumps back to the top of the loop to start the next one.
An infinite loop that never hits a break will run until your program crashes or is terminated. That’s what causes an app to freeze.
count == 5 but you never increment count, it will loop forever. Always double-check that something inside your loop is moving toward the exit condition.Variations and Syntax Patterns
There are several different ways an infinite loop can appear in Swift. Knowing each form helps you recognize them both when you’re writing them intentionally and when they sneak in by accident.
while true {
// runs forever until break is hit
if someCondition {
break
}
}repeat {
print("This runs at least once")
if someCondition {
break
}
} while truerepeat-while loop always executes its body first, then checks the condition. With while true, the body runs at least once and then loops forever until a break is hit. Use this when your logic needs to execute once before you can evaluate a stopping condition.// Dangerous: modifying the collection you're iterating
var items = [1, 2, 3]
var index = 0
// This pattern can loop forever if index never reaches items.count
while index < items.count {
items.append(items[index] * 2) // grows the array every iteration
index += 1
}index < items.count, but the loop also adds to items on every pass. The count keeps growing, so index never catches up. The fix is to capture the count before the loop starts: let originalCount = items.count.// This will crash with a stack overflow
func countdown(from: Int) {
print(from)
countdown(from: from - 1) // no base case — goes forever
}
// The fix: add a base case
func countdownFixed(from: Int) {
guard from > 0 else { return }
print(from)
countdownFixed(from: from - 1)
}// Technically finite, but practically infinite
for _ in 1...Int.max {
print("still going...")
}
// Better to use while true with an explicit break conditionInt.max (the largest possible integer in Swift) as the upper bound of a range. It will technically finish after about 9.2 quintillion iterations — but in practice, it’s effectively infinite. Avoid this pattern. If you want an infinite loop, use while true and be explicit about it.func pollForUpdates() {
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
// do some work...
print("Checking for updates")
// reschedule itself
pollForUpdates()
}
}How Infinite Loops Appear in Real iOS Code
Here’s something that might surprise you: your iOS app is essentially running inside an infinite loop right now. Apple’s RunLoop is a controlled loop that keeps your app alive, listening for user input, network events, timers, and system messages.
You don’t write this loop yourself — Apple’s UIKit framework handles it for you. But understanding that it exists helps you reason about why your app stays open between user interactions rather than exiting after each action.
Here’s a simplified version of what that loop looks like conceptually:
// Conceptual illustration — not actual Swift/iOS code
while appIsRunning {
let event = waitForNextEvent() // blocks until something happens
processEvent(event) // handle tap, swipe, timer, etc.
updateUI() // redraw the screen if needed
}
// When the user force-quits the app, appIsRunning becomes falseNow let’s look at a more hands-on example — a real place in iOS development where you might write your own intentional loop. Imagine a function that retries a network request a certain number of times before giving up:
func fetchDataWithRetry(maxAttempts: Int) async throws -> Data {
var attempts = 0
while true {
do {
attempts += 1
let data = try await makeNetworkRequest()
return data // success — exits the loop by returning
} catch {
if attempts >= maxAttempts {
throw error // give up and propagate the error
}
// Otherwise, try again
print("Attempt \(attempts) failed. Retrying...")
}
}
}
// Placeholder so the code compiles
func makeNetworkRequest() async throws -> Data {
return Data()
}This is a textbook use of while true in production Swift code. The loop keeps trying until it either succeeds (exits via return) or runs out of attempts (exits via throw). Both paths are well defined — there’s no way for this loop to run forever.
The pattern here is important: every time you write while true, ask yourself “what are all the ways this loop can exit?” If you can’t answer that clearly, the loop probably needs a redesign.
Common Mistakes to Avoid
Here are the most common infinite loop problems that trip up beginners. Most of them come down to one thing: losing track of your exit condition.
// Bug: increments by 2, skips over the target value
var n = 0
while n != 5 {
n += 2 // goes 0, 2, 4, 6, 8... never equals 5
}
// Fix: use >= instead of !=
var n = 0
while n < 5 {
n += 2 // stops when n reaches 6, which is >= 5
}!= as a loop condition is risky when your variable skips over values. If it jumps past the target, the condition is never met and the loop runs forever. Prefer < or <= for numeric loops — they’re safer because they don’t require an exact match.// In a SwiftUI View — this causes an infinite loop
struct BadView: View {
@State private var count = 0
var body: some View {
count += 1 // mutating state here triggers a re-render
return Text("Count: \(count)") // which calls body again...
}
}
// Fix: move side effects into .onAppear or .task
var body: some View {
Text("Count: \(count)")
.onAppear { count += 1 }
}@State variable inside body triggers SwiftUI to re-render the view, which calls body again, which mutates the state again — forever. Always keep side effects out of body. Use .onAppear, .task, or event handlers instead.// Bug: count is never incremented, condition stays false forever
var count = 0
while count < 10 {
print("Working...")
// forgot: count += 1
}
// Fix: always increment inside the loop
var count = 0
while count < 10 {
print("Working...")
count += 1 // now the condition will eventually become false
}true, so the loop never ends. A good habit: always write the increment line immediately after you write the loop condition.// Bug: break exits the inner for loop, not the outer while loop
var running = true
while running {
for i in 1...3 {
if i == 2 {
break // only breaks the for loop, while loop continues!
}
}
}
// Fix: use a labeled break to exit the outer loop
outerLoop: while running {
for i in 1...3 {
if i == 2 {
break outerLoop // now breaks the while loop
}
}
}break only exits the innermost loop. This is a common source of accidental infinite loops. Swift supports labeled breaks — you attach a name to the outer loop and use break labelName to exit it from anywhere inside the nested structure.Quick Reference
Here’s a cheat sheet of the infinite loop patterns you’ll encounter in Swift and what each one does:
| Syntax | What It Does |
|---|---|
| while true { } | Explicit infinite loop. Runs until a break, return, or throw exits it. |
| repeat { } while true | Same as while true, but the body always executes at least once before the condition is checked. |
| break | Immediately exits the innermost loop (or switch statement). |
| continue | Skips the rest of the current loop iteration and restarts from the top. |
| break labelName | Exits a specific outer loop when used inside nested loops. Attach the label before the outer loop keyword. |
| return (inside a loop) | Exits the entire function, which also stops any loop currently running inside it. |
| throw (inside a loop) | Throws an error and exits the function, stopping any running loop as a side effect. |
| while condition != true | A standard while loop that can accidentally become infinite if the condition is never met exactly. |
Using AI to Go Deeper with Infinite Loops
AI coding tools are part of how developers work today. Knowing the right things to ask — and how to use the output — is a skill in itself. These prompts are designed to help you deepen your understanding of infinite loops, not bypass it.
Summary
Here’s a quick recap of what you learned about infinite loops in Swift:
- An infinite loop is a loop with a condition that never becomes false on its own
- The most common intentional infinite loop in Swift is
while true { } - Use
breakto exit a loop,continueto skip an iteration, and labeled breaks for nested loops - Accidental infinite loops are usually caused by forgetting to update the loop variable, skipping past an exact exit value, or mutating state inside a SwiftUI body
- Your iOS app’s run loop is a controlled infinite loop that Apple manages for you — it keeps the app alive and responsive
- Every time you write
while true, be able to name all the ways the loop can exit
The best way to get comfortable with this is to write a few intentional infinite loops and practice different exit strategies: break, return, and throw. Try building that retry function from the practical example — it’s a pattern you’ll actually use.
Once you’re solid on loops, a great next concept to explore is Swift closures — closures and loops work hand in hand in a lot of real iOS code, and understanding both will open up a lot of possibilities.

