SwiftUI ForEach with .indices() does not update after onDelete
Asked Answered
W

1

7

my problem is: I have simple array with some Items. I want to display a List with these items using a ForEach with .indices(). (This is because my actual problem handles with Toggle in a List and for the isOn binding I need the index to address a model that is bound to an EnvironmentObject). So the solution to loop over the array items is no possible solution for my problem.

The simplified starting point looks like this:

struct ContentView: View {
    @State var items = ["Item1", "Item2", "Item3"]
    
    var body: some View {
        List {
            ForEach(items.indices) {index in
                Text(self.items[index])
            }.onDelete(perform: deleteItem)
        }
    }
    
    func deleteItem(indexSet: IndexSet) {
        self.items.remove(atOffsets: indexSet)
    }
}

If I now try to swipe-delete a row, I get this error message:

Thread 1: Fatal error: Index out of range

Debugging the index value inside the closure, I can see, that the indices of the items-array does not update. For example: If I delete the first row with "Item 1" and inspect the value of index after deleting the row it returns 2 instead of 0 (which is the expected first index of the array). Why is this and how can I fix this problem?

Thanks for your help!

Wow answered 15/7, 2020 at 7:23 Comment(0)
I
6

Just use dynamic content ForEach constructor (_ data: .., id: ...)

ForEach(items.indices, id: \.self) {index in   // << here !!
    Text(self.items[index])
}.onDelete(perform: deleteItem)
Ixion answered 15/7, 2020 at 7:46 Comment(2)
Thanks for your answer, Asperi. It works well. Now I tried your solution with a Model-class that has an array of [Item]. And Item is a struct that conforms to Identifiable and has a Boolean-attribute. Now if I build the same View like above everything is fine. But when I replace the Text()-View with a Toggle() which is controlled by the Boolean-Value, I get another error on delete (this time inside the AppDelegate): Thread 1: Fatal error: Index out of range. What happens here?Wow
This fixed my issue...... With the traditional approach, in the first viewLoad my array has 3 elements, and 3 items are displayed...... In the reload, the array has one item, but the ForEach ran through indices 0, 1, 2. Even though I cold inspect items.count and it was = 1, right before the ForEach.... Weird.....Pyromagnetic

© 2022 - 2024 — McMap. All rights reserved.