Enumeration and ForEach

You want the ability to get the index from an array during a ForEach. Here are some things to consider.

Overview

In order for this to work properly you need to have some unique id witin your collection. This stated in the documentation.

Either the collection’s elements must conform to Identifiable or you need to provide an id parameter to the ForEach initializer.

Lets create some dummy data


import SwiftUI


struct Foo: Identifiable {
   var id: UUID = UUID()
   var name: String
}

let results = [Foo(name: "Example 1"), Foo(name: "Example 2")]

At this point lets see what happens when we enumerate on the list.

let enumeratedList = results.enumerated()
let b = enumeratedList.map({$0})

print(b)
/*
[
    (offset: 0, element: Foo(id: 4E0F77DA-6276-425E-A697-55FDA7F42190, name: "Example 1")), 
    (offset: 1, element: Foo(id: B88C0865-9E90-47B4-899F-9231D8F585D2, name: "Example 2"))
]
*/

Array of Tuples

If you look at the results of b we get an array of tuples that have the keys offset and element. The offset is unique because it’s the index position of that item and we can use that as an ID for the ForEach.

In order to access the element of offset we can use .0. As that is the first element within that tuple.

// Example with an Array of Structs.
ForEach(results.enumerated().map({$0}), id:\.0) { index, item in
        // ... you can pass in the index or item    
}


// Example with Strings
ForEach(["baseball", "basketball", "hockey"].enumerated().map({$0}), id:\.0) { index, item in
      // ... you can pass in the index or item    
 }

Conclusion

Using enumerated() and map will return us a collection of tuples. This can be used to then pass into the ForEach for iterarting over this list.

This can solution can be fine for trying out some data in a collection, but I do suggesting converting the array of tuples into an array of structs. It will make your life much easier. Check out the “Conclusion” on how you could approach this at a blog post on this topic.