3

This is my third question on this issue. So far there was no solution that didn't crash. I want to swipe-delete on a List with Toggles. My (simplified) code looks like this:

struct Item: Identifiable {
    var id = UUID()
    var isOn: Bool
}
struct ContentView: View {
    @State var items = [Item(isOn: true) , Item(isOn: false), Item(isOn: false)]
    
    var body: some View {
        NavigationView {
            List {
                ForEach(items) {item in
                        Toggle(isOn: self.selectedItem(id: item.id).isOn)
                        {Text("Item")}
                }.onDelete(perform: delete)
            }
        }
    }
    
    func delete(at offsets: IndexSet) {
        self.items.remove(atOffsets: offsets)
    }
    
    func selectedItem(id: UUID) -> Binding<Item> {
        guard let index = self.items.firstIndex(where: {$0.id == id}) else {
            fatalError("Item does not exist")
        }
        return self.$items[index]
    }
    
}

I tried different solutions, e.g. with .indices and .enumerated() and looping over the indices. The solution with the func selectedItem() is from https://troz.net/post/2019/swiftui-data-flow/, which is a nice idea to get a Bindable from item.

If I try to swipe-delete the list items, I always get this error:

Thread 1: Fatal error: Index out of range

I'd really like to understand why this happens, but XCodes error messages doesn't really help. I posted similar questions here: SwiftUI ForEach with .indices() does not update after onDelete (see comment) and here: SwiftUI: Index out of range when deleting cells with toggle.

I really hope someone can help on this issue, because I try to find a solution on the internet for a few days but none of the suggested solutions really worked out for me.

Thanks, Nico

1 Answers1

1

Here is fixed part of code (tested with Xcode 11.4 / iOS 13.4)

func selectedItem(id: UUID) -> Binding<Item> {
    guard let index = self.items.firstIndex(where: {$0.id == id}) else {
        fatalError("Item does not exist")
    }

    // Don't use direct biding to array element as it is preserved and
    // result in crash, use computable standalone binding instead !!
    return Binding(get: {self.items[index]}, set: {self.items[index] = $0})
}
Asperi
  • 228,894
  • 20
  • 464
  • 690