swiftswiftui

Why does looping over the indices of an array in ForEach kill scroll performance?


I have a large array of around 50k items where each item conforms to identifiable.

I do not change the array in any way such as rearranging or whatsoever.

If I were to pass it directly to ForEach, list scroll performance is signifcantly smoother than if i were to pass the indices.

I realise the documentation mentions sth to do with the strucutural identity of each cell but I am unable to understand it on why that's the case.

ForEach(myArray, id: \.id) { item in
    MyRowView(item: item)
}

// Extremely choppy scroll
ForEach(myArray.indices, id: \.self) { index in
    MyRowView(item: myArray[index])
}

Solution

  • In short, using ForEach(myArray, id: \.id) gives SwiftUI structural identity for each item — it knows what the data is and can efficiently track and reuse views. This results in smooth scrolling, even with large arrays.

    In contrast, ForEach(myArray.indices, id: \.self) just passes integers. SwiftUI can't associate those indices with the underlying data, so it may unnecessarily recreate views, leading to choppy performance.

    This behavior is explained in detail in the WWDC 2021 video "Demystify SwiftUI" 23:35