Swift Infinite Loops

Your app froze. The spinner is spinning and spinning. You can’t click anything. Somewhere in your code, a loop is running forever — and now you need to understand why.
Written by

Chris C

Updated on

Mar 29 2026

Table of contents

    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:

    LineWhat it does
    var count = 0Sets 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 += 1Increments 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.

    Common gotcha: The most common beginner mistake with loops is forgetting to update the variable that controls the exit condition. If your loop checks 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 The most explicit infinite loop — runs until break
    while true {
        // runs forever until break is hit
        if someCondition {
            break
        }
    }
    This is the most readable way to write an intentional infinite loop. Developers use it when they want to keep something running indefinitely but retain full control over when to stop. You’ll see this pattern in game loops, polling systems, and background tasks.
    repeat-while true Executes the body at least once before checking the condition
    repeat {
        print("This runs at least once")
        if someCondition {
            break
        }
    } while true
    A repeat-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.
    for loop gone infinite An accidental infinite loop hiding in a for-in pattern
    // 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
    }
    This is a sneaky accidental infinite loop. The condition checks 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.
    recursive infinite loop A function that calls itself with no base case
    // 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)
    }
    Recursive functions can create infinite loops if there’s no exit condition. Every function call is added to the call stack, and without a base case, the stack overflows and your app crashes. This is a different kind of infinite loop but has the same result: your app hangs or crashes.
    for _ in 1…Int.max A very long loop that simulates an infinite loop in practice
    // Technically finite, but practically infinite
    for _ in 1...Int.max {
        print("still going...")
    }
    
    // Better to use while true with an explicit break condition
    This uses Int.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.
    DispatchQueue infinite loop Scheduling a task that keeps rescheduling itself
    func pollForUpdates() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            // do some work...
            print("Checking for updates")
            // reschedule itself
            pollForUpdates()
        }
    }
    This is a controlled, intentional infinite loop pattern used in iOS apps. The function calls itself via a delayed dispatch, creating a polling loop that checks for updates every 5 seconds. This is a legitimate pattern for background tasks — but make sure you have a way to stop it, such as a boolean flag that can be set to cancel further rescheduling.

    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 false

    Now 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.

    Mistake 1 Off-by-one: the exit condition is never exactly met
    // 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
    }
    Using != 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.
    Mistake 2 SwiftUI state mutation triggering endless re-renders
    // 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 }
    }
    This is one of the most disorienting SwiftUI bugs for beginners. Mutating a @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.
    Mistake 3 Forgetting to update the loop variable
    // 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
    }
    This is the classic beginner mistake. You write a loop, write the condition, write the body — and forget to move the variable that the condition checks. The condition is always true, so the loop never ends. A good habit: always write the increment line immediately after you write the loop condition.
    Mistake 4 A break inside a nested loop only exits the inner loop
    // 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
            }
        }
    }
    When you have nested loops, 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:

    SyntaxWhat It Does
    while true { }Explicit infinite loop. Runs until a break, return, or throw exits it.
    repeat { } while trueSame as while true, but the body always executes at least once before the condition is checked.
    breakImmediately exits the innermost loop (or switch statement).
    continueSkips the rest of the current loop iteration and restarts from the top.
    break labelNameExits 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 != trueA 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.

    Deepen Your Understanding Use AI as a tutor — no code generation required
    Explain infinite loops to me like I’m a Swift beginner. Use a real-world analogy first, then show me the simplest possible code example and walk through it line by line.
    I think I understand while true loops in Swift but I’m not 100% sure about when to use break vs return vs continue inside them. Can you quiz me on these concepts? Ask me one question at a time and tell me when I get something wrong.
    Build a Practice Example Generate heavily commented code to study and learn from
    Write a short Swift example that uses an infinite loop (while true) in a realistic iOS context like a retry mechanism or a polling function. Add a comment on every line explaining what it does and why — write the comments for a complete beginner to the Swift language.
    Give me 3 different examples of infinite loops in Swift, each one slightly more realistic than the last. The first should be a basic while true with a break. The second should show a real-world use case. The third should show how to avoid an accidental infinite loop. Add inline comments throughout so I can follow the logic.
    Audit Your Own Code Use AI to review code you’ve already written — you stay in the driver’s seat
    Here’s some Swift code I wrote: [paste your code]. Can you check if there are any loops in here that could accidentally become infinite? Explain why for each one you find, and suggest the fix before you show me revised code.
    Review this Swift code for how I’m using loops: [paste your code]. Are there any places where I should be using break or continue but I’m not? Are there any places where the exit condition looks risky? Explain your thinking before suggesting changes.
    Keep yourself in the driver’s seat: If AI generates code for you, make sure you can explain every line of it before you move on. The goal of these prompts is to accelerate your understanding — not to create code you don’t fully grasp.

    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 break to exit a loop, continue to 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.



    Get started for free

    Join over 2,000+ students actively learning with CodeWithChris