# Swift forEach Explained: Iterating with Closures Clearly

## Pro Summary

`forEach(_:)` is a `rethrows` method that takes a synchronous, non-escaping `(Element) throws -> Void` closure. Inside it, `return` acts like `continue`, `break` and `continue` don't compile, and you can't `await`. Use `for`-`in` when you need early exit, `where` filtering, `await`, or typed throws, and keep `forEach` for a single side effect at the end of a functional chain. SwiftUI's `ForEach` is a different thing: a view that builds child views from data.

```
func forEach(_ body: (Element) throws -> Void) rethrows
```

Gotchas:

- Because `forEach` is `rethrows`, typed errors are erased: calling a `throws(ParseError)` function inside it makes the whole call throw `any Error`, so it won't compile inside a `throws(ParseError)` function, while a `for`-`in` loop keeps the typed error (SE-0413).
- `items.forEach { await process($0) }` fails with "cannot pass function of type '(Int) async -> Void' to parameter expecting synchronous function type", and `AsyncSequence` has no `forEach` at all, so iterate it with `for await`.
- `Set` and `Dictionary` iteration order changes between process launches because hashing uses a per-execution random seed (SE-0206), so sort before printing or asserting on output; `SWIFT_DETERMINISTIC_HASHING=1` is for debugging only.
- The closure parameter is immutable, so `structs.forEach { $0.count += 1 }` doesn't compile; mutate through indices (`for i in array.indices { array[i].count += 1 }`) or build a new array with `map`.

Primary sources:

- [Sequence (Swift standard library, Apple)](https://developer.apple.com/documentation/swift/sequence)
- [The Swift Programming Language: For-In Loops](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow/#For-In-Loops)
- [SE-0206: Hashable Enhancements (per-execution random seeding)](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0206-hashable-enhancements.md)
- [SE-0413: Typed throws](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0413-typed-throws.md)

Source: https://devdocs10.com/articles/swift/swift-foreach  
By Murat Bo · Updated 2026-10-17 · DevDocs10 (https://devdocs10.com)

Swift’s `forEach` method lets you iterate over a collection by passing a closure that runs once for each element. It is concise and expressive, but it behaves differently from a normal `for-in` loop in important ways. In this article, you will learn how `forEach` works, how to write it correctly, when it is a good choice, and when a regular loop is better.

> **Quick answer:** In Swift, `forEach` is a method on sequences and collections that executes a closure for every element. Use it for simple, readable iteration, but use `for-in` when you need `break`, `continue`, or early loop control.

> **Difficulty:** Beginner
>
> **Helpful to know first:** You’ll understand this better if you know basic Swift syntax, how arrays and dictionaries store values, and what a closure is at a simple level.

## 1. What Is forEach?

`forEach` is a method provided by Swift sequences and collections. Instead of writing a loop body directly, you pass a closure that Swift calls for each element in order.

- It works on types such as arrays, sets, dictionaries, and ranges.
- It takes one closure argument.
- The closure receives each element one at a time.
- It is often used with trailing closure syntax for readability.
- It is not a perfect replacement for `for-in` because loop control works differently.

For beginners, the main idea is simple: `forEach` says “do this action for every item.”

If you have already used `for-in`, think of `forEach` as a more functional style of iteration. The biggest comparison to remember is this: `forEach` is great for straightforward work on every element, while `for-in` gives you more control over the loop itself.

## 2. Why forEach Matters

`forEach` matters because it gives you a compact and expressive way to iterate through data. In real code, that often means fewer temporary names, less visual noise, and a clearer “apply this action to each item” intent.

It is especially useful when:

- You want to print, transform, inspect, or trigger a side effect for each element.
- You want code that reads like a sequence of operations.
- You are already working with closures and higher-order methods such as `map`, `filter`, or `sorted`.

It is less suitable when:

- You need to stop early after finding a match.
- You need `continue` to skip to the next loop iteration in the usual loop sense.
- You need complex branching that becomes hard to read inside a closure.

So `forEach` matters not because it replaces every loop, but because it is a useful tool for a specific style of iteration.

## 3. Basic Syntax

### Basic array syntax

Here is the minimal working form of `forEach` with an array. The closure receives each value in the array.

```swift
let numbers = [1, 2, 3]

numbers.forEach { number in
    print(number)
}
```

Output (tested with Swift 6.4):

```text
1
2
3
```

This prints each element in order. The parameter name `number` is the current item being processed.

### How to read it

You can read the code as: “for each `number` in `numbers`, print the number.”

The parts are:

- `numbers`: the sequence being iterated
- `forEach`: the method that performs iteration
- `{ number in ... }`: the closure run for each element

### Single-expression closure shorthand

When the closure is very short, you can use shorthand argument names. This is valid Swift, though beginners often find the named version easier to read.

```swift
let names = ["Ava", "Liam", "Noah"]

names.forEach {
    print($0)
}
```

Output (tested with Swift 6.4):

```text
Ava
Liam
Noah
```

This version works the same way, but `$0` refers to the first closure parameter automatically.

## 4. Step-by-Step Examples

### Example 1: Printing every value in an array

This is the most direct use of `forEach`. You have a list of items and want to perform the same action for each one.

```swift
let cities = ["Paris", "Tokyo", "Nairobi"]

cities.forEach { city in
    print("City: \(city)")
}
```

Output (tested with Swift 6.4):

```text
City: Paris
City: Tokyo
City: Nairobi
```

The closure runs three times, once for each city. This is a clean choice when you only need a simple side effect like printing or logging.

### Example 2: Working with a range

`forEach` also works on ranges because ranges are sequences in Swift.

```swift
(1...5).forEach { value in
    print("Count: \(value)")
}
```

Output (tested with Swift 6.4):

```text
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
```

This runs the closure for values 1 through 5. It is useful when you want a fixed number of repeated actions.

### Example 3: Iterating through a dictionary

When you use `forEach` on a dictionary, each element is a key-value pair.

```swift
let scores = ["Ana": 92, "Ben": 85, "Cara": 99]

scores.forEach { entry in
    print("\(entry.key): \(entry.value)")
}
```

Output (tested with Swift 6.4):

```text
Ben: 85
Cara: 99
Ana: 92
```

This gives you one dictionary element at a time. Remember that dictionary order should not be relied on unless you explicitly create sorted output.

### Example 4: Using enumerated() with forEach

If you need both the index and the value, combine `enumerated()` with `forEach`.

```swift
let tasks = ["Plan", "Build", "Test"]

tasks.enumerated().forEach { index, task in
    print("Step \(index + 1): \(task)")
}
```

Output (tested with Swift 6.4):

```text
Step 1: Plan
Step 2: Build
Step 3: Test
```

This is useful when display order matters or when you need numbered output. The closure receives both values because `enumerated()` produces a sequence of index-element pairs.

## 5. Practical Use Cases

- Printing or logging every item in an array of values during debugging.
- Applying a side effect to each element, such as updating counters or collecting statistics.
- Displaying numbered output by combining `enumerated()` with `forEach`.
- Processing dictionary entries when you want to inspect keys and values together.
- Running a simple action over a range, such as repeating a test setup a fixed number of times.
- Writing clear “do this for each item” code when early exit is not needed.

## 6. Common Mistakes

### Mistake 1: Expecting break to work inside forEach

A very common beginner mistake is treating `forEach` exactly like a `for-in` loop. Although both iterate, `forEach` is a method that executes a closure, so loop control keywords do not behave the same way.

**Problem:** `break` cannot be used to stop a `forEach` closure the way it stops a normal loop. If you need early exit, this is the wrong tool.

```swift
let numbers = [1, 2, 3, 4]

numbers.forEach { number in
    if number == 3 {
        break
    }
    print(number)
}
```

**Fix:** Use a `for-in` loop when you need to stop iterating early.

```swift
let numbers = [1, 2, 3, 4]

for number in numbers {
    if number == 3 {
        break
    }
    print(number)
}
```

Output (tested with Swift 6.4):

```text
1
2
```

The corrected version works because `for-in` supports loop control statements like `break`.

### Mistake 2: Thinking return exits the outer function

Inside a `forEach` closure, `return` exits only that closure call, not the surrounding function. Many developers expect it to stop the whole operation.

**Problem:** This code suggests that finding an empty string should stop the enclosing function, but `return` only leaves the current closure execution, so later elements still run.

```swift
func printNames(_ names: [String]) {
    names.forEach { name in
        if name.isEmpty {
            return
        }
        print(name)
    }

    print("Done")
}
```

**Fix:** If you need to stop processing completely, use `for-in` and return from the outer function directly.

```swift
func printNames(_ names: [String]) {
    for name in names {
        if name.isEmpty {
            return
        }
        print(name)
    }

    print("Done")
}
```

The corrected version works because the `return` is now inside the function body’s loop, not inside a separate closure scope.

### Mistake 3: Using forEach when a transformed result is needed

`forEach` is for performing actions, not for building a new collection automatically. Beginners sometimes expect it to return transformed values.

**Problem:** This code expects `forEach` to produce a new array, but `forEach` returns `Void`, so there is no transformed result.

```swift
let numbers = [1, 2, 3]

let doubled = numbers.forEach { number in
    number * 2
}
```

**Fix:** Use `map` when you want to create a new array from each element.

```swift
let numbers = [1, 2, 3]

let doubled = numbers.map { number in
    number * 2
}

print(doubled)
```

Output (tested with Swift 6.4):

```text
[2, 4, 6]
```

The corrected version works because `map` returns a new collection containing each transformed value.

## 7. Best Practices

### Practice 1: Use forEach only for straightforward side effects

`forEach` is most readable when the closure does one simple thing, such as printing, logging, or updating a small piece of state.

```swift
let messages = ["Start", "Loading", "Done"]

messages.forEach { message in
    print(message)
}
```

Output (tested with Swift 6.4):

```text
Start
Loading
Done
```

This works well because the intent is obvious: perform the same simple action for every item.

### Practice 2: Prefer named closure parameters over $0 for learning and clarity

Shorthand syntax is compact, but a named parameter is often easier to understand, especially when the closure body spans multiple lines.

```swift
let prices = [9.99, 14.50, 20.00]

prices.forEach { price in
    print("Price: \(price)")
}
```

Output (tested with Swift 6.4):

```text
Price: 9.99
Price: 14.5
Price: 20.0
```

This style is usually clearer than relying on `$0`, especially for beginners and team code.

### Practice 3: Switch to for-in when control flow becomes important

If your iteration needs skipping, stopping, nested branching, or clear early exits, a regular loop is often easier to maintain.

```swift
let values = [3, 6, 9, 12]

for value in values {
    if value == 9 {
        break
    }
    print(value)
}
```

Output (tested with Swift 6.4):

```text
3
6
```

This is a best practice because code should match the job. `forEach` is elegant, but not at the cost of control and clarity.

## 8. Limitations and Edge Cases

- `forEach` cannot use `break` or `continue` like a normal `for-in` loop.
- `return` inside the closure only exits the current closure execution, not the outer function.
- `forEach` returns `Void`, so it is not for creating transformed collections. Use `map`, `compactMap`, or `filter` instead.
- Dictionary iteration order should not be relied on unless you sort the data first.
- With complex logic, nested conditions inside the closure can become harder to read than a standard loop.
- If you see “cannot convert value of type '()'” in code using `forEach`, you may be trying to assign its result as though it returns a value.

## 9. Practical Mini Project

This mini project prints a numbered shopping list, calculates a running total, and highlights expensive items. It shows a realistic use of `forEach` for side effects.

```swift
struct Item {
    let name: String
    let price: Double
}

let items = [
    Item(name: "Notebook", price: 4.50),
    Item(name: "Headphones", price: 29.99),
    Item(name: "Pen", price: 1.20)
]

var total: Double = 0.0

print("Shopping List")

items.enumerated().forEach { index, item in
    print("\(index + 1). \(item.name) - $\(item.price)")

    if item.price > 20 {
        print("  Premium item")
    }

    total += item.price
}

print("Total: $\(total)")
```

Output (tested with Swift 6.4):

```text
Shopping List
1. Notebook - $4.5
2. Headphones - $29.99
  Premium item
3. Pen - $1.2
Total: $35.69
```

This example uses `enumerated()` to show item numbers, uses `forEach` to process each item, and updates a running total outside the closure. It is a good example of the kind of side-effect-driven task that `forEach` handles well.

## 10. Key Points

- `forEach` runs a closure once for every element in a sequence.
- It is best for simple, readable actions performed on each item.
- Use trailing closure syntax to keep the code concise.
- Choose `for-in` instead when you need `break`, `continue`, or early exit from the surrounding function.
- `forEach` returns `Void`, so it does not build a new collection.
- Use `map` for transformation and `filter` for selection, not `forEach`.

## 11. Practice Exercise

Try this exercise to confirm that you understand how `forEach` works.

- Create an array of five temperatures.
- Use `forEach` to print each temperature.
- Keep a running sum in a separate variable.
- After the loop, print the average temperature.

**Expected output:** Each temperature should be printed, followed by the average.

**Hint:** Declare a mutable variable with `var` before the `forEach` call, then add each temperature inside the closure.

```swift
let temperatures = [18.5, 21.0, 19.5, 23.0, 20.0]
var sum: Double = 0.0

temperatures.forEach { temperature in
    print("Temperature: \(temperature)")
    sum += temperature
}

let average = sum / Double(temperatures.count)
print("Average: \(average)")
```

Output (tested with Swift 6.4):

```text
Temperature: 18.5
Temperature: 21.0
Temperature: 19.5
Temperature: 23.0
Temperature: 20.0
Average: 20.4
```

## 12. Final Summary

Swift’s `forEach` method is a clean way to iterate with closures when your goal is simple, repeated action on every element. It works well with arrays, dictionaries, ranges, and other sequences, and it becomes especially readable when paired with trailing closure syntax.

The most important thing to remember is that `forEach` is not the same as `for-in`. If you need loop control such as `break`, more obvious branching, or early exit from a function, a regular loop is usually the better choice. If you need to produce a new collection, use tools like `map` instead.

Once you are comfortable with `forEach`, a useful next step is learning how it differs from other sequence methods such as `map`, `filter`, and `reduce`. That will help you choose the right iteration tool for each task.

## Where AI Coding Assistants Get This Wrong

- Often suggested: Writes `ids.forEach { id in await store.load(id) }` when converting callback code to async/await.
  Instead: Use `for id in ids { await store.load(id) }` for sequential work, or `withTaskGroup(of:)` / `withThrowingTaskGroup(of:)` when the calls should run concurrently. (`forEach` takes a synchronous closure, so the async version doesn't compile.)
- Often suggested: Uses `names.forEach { Text($0) }` inside a SwiftUI `body` or `VStack`.
  Instead: Use the `ForEach` view: `ForEach(names, id: \.self) { Text($0) }`, or use `Identifiable` elements and drop `id:`. (`forEach` returns `Void`, so the builder fails with "type '()' cannot conform to 'View'".)
- Often suggested: Puts `return` inside `forEach` to stop searching once a match is found, or sets a `found` flag and keeps iterating.
  Instead: Use `first(where:)`, `contains(where:)` or `firstIndex(where:)`, or a `for`-`in` loop with `return` or `break`. (`return` only ends the current closure call, so the rest of the sequence is still visited.)
