Give your simulator superpowers

RocketSim: An Essential Developer Tool
as recommended by Apple

SwiftUI ForEach Explained with Code Examples

If you’re building dynamic lists or repeating UI components in SwiftUI, there’s a high chance you’re already using the SwiftUI ForEach view element. It’s a powerful, yet sometimes misunderstood, view element in SwiftUI.

This article will help you understand how ForEach works and when and how to use it. We’ll also dive into index-based iteration and how the Identifiable protocol can help you out.

What is SwiftUI ForEach?

The SwiftUI ForEach view element allows you to iterate over a collection and generate a view for each.
The SwiftUI ForEach view element allows you to iterate over a collection and generate a view for each.

The SwiftUI ForEach view allows you to iterate over a collection and generate views for each element. It’s especially useful when working with ListLazyVStack, or any container that supports multiple children.

struct ContentView: View {
    let names = ["Antoine", "Maaike", "Sep", "Jip"]

    var body: some View {
        ForEach(names, id: \.self) { name in
            Text(name)
        }
    }
}

In the above example, we iterate over all names in the collection by using \.self as the identifier since String conforms to Hashable. For custom types, it’s better to provide a unique identifier via the Identifiable protocol.

FREE 5-day email course: The Swift Concurrency Playbook by Antoine van der Lee

FREE 5-Day Email Course: The Swift Concurrency Playbook

A FREE 5-day email course revealing the 5 biggest mistakes iOS developers make with with async/await that lead to App Store rejections And migration projects taking months instead of days (even if you've been writing Swift for years)

ForEach with Identifiable Data

Iterating over a collection using the Identifiable protocol is the cleanest approach. It allows us to remove the \.self identifier and rely on the id property requirement of the Identifiable protocol instead:

struct ContentView: View {
    let people = [
        Person(id: UUID(), name: "Antoine"),
        Person(id: UUID(), name: "Maaike")
    ]

    var body: some View {
        ForEach(people) { person in
            Text(person.name)
        }
    }
}

Using Identifiable helps SwiftUI track view identity across state updates and avoid unnecessary redraws.

Using ForEach in Lists

When used inside a List, the SwiftUI ForEach view becomes essential for rendering dynamic rows:

List {
    ForEach(people) { person in
        HStack {
            Image(systemName: "person")
            Text(person.name)
        }
    }
}

Iterating with an Index

By using an enumerated array, you can iterate over items and their indexes:

ForEach(Array(people.enumerated()), id: \.offset) { index, person in
    Text("Index \(index): \(person.name)")
}

This can occasionally be useful if you need to have the index at hand while performing index-based view styling, for example.

Conclusion

SwiftUI ForEach is an essential part of building dynamic interfaces. It’s recommended to use it in combination with the Identifiable protocol, but using the id parameter should work in most cases too. You can use an enumerated array if you also need to have the index for each item while iterating.

If you’re interested in learning more about other SwiftUI elements, I recommend the following articles:

If you want to improve your SwiftUI knowledge, even more, check out the SwiftUI category page. Feel free to contact me or tweet me on Twitter if you have any additional tips or feedback.

Thanks!