Element and Index: Enumerated ForEach in Swift UI

Looping through an array of elements to display them in a list is a very common and, thus, quite straightforward task in SwiftUI. One might think accessing the index of an elemen should be just as simple.

But it's not… so let's discover it together.

To have the element and index available in our loop, we cannot just iterate over the Array as is. Instead, we have to create an enumerated version of it to create an EnumeratedSequence. Doing that, the compiler will reward us with the following warning:

Generic struct 'ForEach' requires that 'EnumeratedSequence<[String]>' conform to 'RandomAccessCollection'

To resolve this issue, we can simply cast the Sequence back to an Array like so:

Array(fruits.enumerated())

In case you are eager to learn more about, what's happening in detail when we convert our array to an EnumeratedSequence and back, please find more information down below.

The final list example looks like the following:

struct EnumeratedListView: View {
    var body: some View {

        let fruits = ["Apple", "Orange", "Banana"]

        List{
            ForEach(Array(fruits.enumerated()), id: \.offset) { index, fruit in
                Text("\(index): \(fruit)").tag(index)
            }
        }
    }
}

I hope that helps you deal with that pesky problem and makes you sleep better at night.

Happy Coding!

XOXO, Christian 👨🏻‍💻


Enumerating an Array

The enumerated() function is called on an array (or any other collection) and returns a sequence of tuples, where the first element of each tuple is the index of the corresponding element in the original array, and the second element is the value from the original array.

In the given example, when you call fruits.enumerated(), it creates an enumerated sequence, with each tuple containing the index and the element from the original array. However, to use this enumerated sequence in the ForEach view in SwiftUI, we need to convert it to an array. That's because ForEach expects a data source that conforms to the RandomAccessCollection protocol, which EnumeratedSequence does not conform to.

By using Array(yourArray.enumerated()), you convert the enumerated sequence back to an array of tuples, which conforms to the RandomAccessCollection protocol. This allows you to use it as a data source for ForEach without any issues. Inside the loop, you can then access both the index and the element for each item in the array.

The resulting array looks as follows:

[(0, "Apple"), (1, "Orange"), (2, "Banana")]
EnumeratedSequence | Apple Developer Documentation
An enumeration of the elements of a sequence or collection.