# How to Write a For Loop in Swift 3 for an Array You Modify During Iteration

> Learn how to write a for loop in Swift 3 that safely modifies an array during iteration. Discover methods like index-based while loops and enumerated() for in-place mutations.

- Repository: [The Swift Programming Language/swift](https://github.com/swiftlang/swift)
- Tags: how-to-guide
- Published: 2026-02-12

---

**To safely modify an array while iterating in Swift 3, avoid standard `for-in` loops and instead use an index-based `while` loop, iterate over a copy, or use `enumerated()` for in-place mutations.**

When you write a for loop in Swift 3 for an array that you modify during the for loop, you must avoid the standard `for-in` syntax. The Swift compiler implements `for-in` as fast enumeration over the `Sequence` protocol, obtaining an iterator once before the loop begins. Mutating the underlying collection during iteration invalidates this iterator, leading to undefined behavior or runtime crashes.

## Why You Cannot Mutate an Array During a Standard For-In Loop

In Swift 3, the `for ... in` construct relies on fast enumeration over any type conforming to `Sequence`. According to the Swift compiler source in [`lib/ASTGen/Sources/ASTGen/Stmts.swift`](https://github.com/swiftlang/swift/blob/main/lib/ASTGen/Sources/ASTGen/Stmts.swift), specifically the `generate(forStmt:)` method, the compiler rewrites the loop into calls to the collection’s iterator. Because the iterator is obtained **once** before the loop starts, mutating the underlying array while the iterator is active invalidates the iteration state. This yields undefined behavior: elements may be skipped, or your app may crash with an iterator invalidation error.

## Safe Patterns to Modify an Array While Iterating in Swift 3

To safely write a for loop in Swift 3 for an array you modify during the loop, use one of these four idiomatic approaches. Each avoids iterator invalidation by either decoupling the iteration from the mutation or by using index-based access that bypasses the `Sequence` iterator.

### Iterate Over a Copy of the Array

Create a snapshot of the array before looping. Mutations apply to the original array, while the loop iterates over the immutable copy.

```swift
var numbers = [1, 2, 3, 4, 5]
let snapshot = numbers               // copy of the current state

for n in snapshot {
    if n % 2 == 0 {                 // remove even numbers from original
        numbers.removeAll(where: { $0 == n })
    }
}
print(numbers)   // → [1, 3, 5]

```

This technique is best when the array fits comfortably in memory and you need to remove elements based on a condition.

### Use an Index-Based While Loop

Manually manage an integer index to traverse the array. This allows you to insert or remove elements and adjust the index accordingly to avoid skipping elements or accessing out-of-bounds indices.

```swift
var items = [10, 20, 30, 40]
var i = 0

while i < items.count {
    if items[i] == 20 {
        items.append(25)            // add a new element
    }
    if items[i] == 30 {
        items.remove(at: i)         // remove current element
        continue                    // skip i+=1 because array shifted left
    }
    i += 1
}
print(items)     // → [10, 20, 25, 40]

```

This approach is essential when you need to insert or delete elements at arbitrary positions during iteration.

### Modify Elements In-Place with enumerated()

Use `enumerated()` when you only need to update existing elements without changing the array’s length. This provides both the index and the element, allowing in-place mutation.

```swift
var letters = ["a", "b", "c"]

for (idx, ch) in letters.enumerated() {
    letters[idx] = ch.uppercased()   // modify element in place
}
print(letters)   // → ["A", "B", "C"]

```

Note that `enumerated()` is safe for value updates but will crash if you attempt to append or remove elements during the loop.

### Control Iteration with stride

For explicit index control similar to C-style loops, use `stride` or a range to access elements by index. This recomputes the count each pass or stores it once, giving you direct array access.

```swift
var numbers = [1, 2, 3, 4, 5]

for idx in stride(from: 0, to: numbers.count, by: 1) {
    if numbers[idx] < 3 {
        numbers[idx] *= 10
    }
}
print(numbers)   // → [10, 20, 3, 4, 5]

```

This pattern is useful when you need to skip indices or modify the loop variable based on runtime conditions.

## Key Source Files in the Swift Repository

Understanding the implementation details helps explain why these patterns are necessary. The Swift compiler and standard library source code reveals how iteration and mutation interact.

- **[`lib/ASTGen/Sources/ASTGen/Stmts.swift`](https://github.com/swiftlang/swift/blob/main/lib/ASTGen/Sources/ASTGen/Stmts.swift)**: Contains the `generate(forStmt:)` method that transforms `for-in` loops into iterator-based code. This shows how the compiler obtains the iterator once before the loop begins, making mutation unsafe.
- **[`stdlib/public/core/Array.swift`](https://github.com/swiftlang/swift/blob/main/stdlib/public/core/Array.swift)**: Implements the `Array` type, including subscripting and mutating methods. This file demonstrates how arrays provide fast random access, making index-based loops efficient.
- **[`lib/Sema/SyntacticElementTarget.cpp`](https://github.com/swiftlang/swift/blob/main/lib/Sema/SyntacticElementTarget.cpp)**: Defines the `ForStmt` syntax node used by the parser, showing the AST structure of loop statements.
- **[`test/SILGen/sil_locations.swift`](https://github.com/swiftlang/swift/blob/main/test/SILGen/sil_locations.swift)**: Contains unit tests for loop generation, including `testForStmt()`, which exercises the compiler’s SIL generation for loops.

## Summary

- **Never mutate an array during a standard `for-in` loop** in Swift 3. The compiler generates an iterator once at the start in [`lib/ASTGen/Sources/ASTGen/Stmts.swift`](https://github.com/swiftlang/swift/blob/main/lib/ASTGen/Sources/ASTGen/Stmts.swift); mutating the array invalidates this iterator and causes undefined behavior.
- **Iterate over a copy** when you need to remove elements based on conditions and the array fits in memory.
- **Use an index-based `while` loop** when inserting or deleting elements at arbitrary positions, manually adjusting the index after mutations.
- **Use `enumerated()`** only for in-place value updates, not for changing the array length.
- **Use `stride` or range-based loops** for explicit index control similar to C-style for loops.

## Frequently Asked Questions

### Can I use for-in to remove elements from an array in Swift 3?

No. Using `for-in` to remove elements directly from the array being iterated causes iterator invalidation. The compiler generates code that calls `makeIterator()` once before the loop starts in [`lib/ASTGen/Sources/ASTGen/Stmts.swift`](https://github.com/swiftlang/swift/blob/main/lib/ASTGen/Sources/ASTGen/Stmts.swift). Removing elements during iteration corrupts the iterator state, leading to skipped elements or runtime crashes. Instead, iterate over a copy or use an index-based loop.

### What happens if I modify an array during fast enumeration?

Modifying an array during fast enumeration produces undefined behavior. The Swift 3 compiler implements `for-in` as fast enumeration over the `Sequence` protocol, obtaining an iterator once before entering the loop body. As implemented in [`stdlib/public/core/Array.swift`](https://github.com/swiftlang/swift/blob/main/stdlib/public/core/Array.swift), mutating the collection while an iterator is active invalidates the iteration state. Your program may skip elements, process elements twice, or crash with a memory access error.

### Is enumerated() safe for all types of array modifications?

No. The `enumerated()` method is only safe for in-place mutations where you update existing elements without changing the array's length. The method returns a sequence of tuples containing the index and element, but the underlying array still uses the same iterator mechanism. You can safely modify `array[idx] = newValue`, but calling `append()`, `remove()`, or `insert()` during an `enumerated()` loop invalidates the iterator and causes undefined behavior.

### Where is the for-in loop implemented in the Swift compiler?

The `for-in` loop is implemented in the Swift compiler's AST generation phase. The primary file is [`lib/ASTGen/Sources/ASTGen/Stmts.swift`](https://github.com/swiftlang/swift/blob/main/lib/ASTGen/Sources/ASTGen/Stmts.swift), which contains the `generate(forStmt:)` method. This method transforms the `for-in` syntax into iterator-based code that calls `makeIterator()` once and then repeatedly calls `next()` until the sequence is exhausted. The parser defines the `ForStmt` syntax node in [`lib/Sema/SyntacticElementTarget.cpp`](https://github.com/swiftlang/swift/blob/main/lib/Sema/SyntacticElementTarget.cpp), and the SIL generation is tested in [`test/SILGen/sil_locations.swift`](https://github.com/swiftlang/swift/blob/main/test/SILGen/sil_locations.swift).