1

when try to remove item in list from modal view, gets crash Thread 1: Fatal error: Index out of range

for example,

  1. delete 1 -> 2 -> 3 gets crash
  2. delete 2 -> 1 gets crash
  3. delete 3 gets crash

if comment out textfield part, there is no crash. not really sure what's going on...

struct ContentView: View {
    @State var strs = ["1", "2", "3"]
    @State var showingDetail: Bool = false
    var body: some View {
        List {
            ForEach(Array(strs.enumerated()), id: \.element) { index, str in
                VStack {
                    Button(action: {
                        self.showingDetail.toggle()
                    }) {
                        Text("show modal")
                            .sheet(isPresented: self.$showingDetail) {
                                ModalView(showingDetail: self.$showingDetail, strs:self.$strs,
                                          index: index)
                        }
                        TextField("", text:self.$strs[index])
                    }
                }
            }
        }
    }
}

struct ModalView: View {
    @Binding var showingDetail: Bool
    @Binding var strs: [String]
    var index: Int = 0
    var body: some View {
        Button(action: {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                self.strs.remove(at: self.index)
            }
            self.showingDetail.toggle()
        }) {
            Text("delete")
        }
    }
}

yukim
  • 11
  • 1

2 Answers2

1

The issue is due to view update order. Use instead the following variant for TextField

TextField("", text: Binding(get: { self.strs[index] },
                            set: { self.strs[index] = $0 }))
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Glory to Ukraine! But better need provide default value: TextField("", text: Binding(get: { viewModel.videoMarks[safe: index]?.text ?? "" }, set: { viewModel.videoMarks[index].text = $0 })) extension Collection { /// Returns the element at the specified index if it is within bounds, otherwise nil. subscript (safe index: Index) -> Element? { return indices.contains(index) ? self[index] : nil } } – AndrewSas Dec 08 '22 at 08:18
0

When you delete the element in an array the number of elements in the array reduces. So, when you delete the first element ie., index 0 then there are only 2 more left. Now you could delete the element at index 1 which is the last element, and the array is left with only 1 element at index 0. So when you try to access the third element at index 2 you get a crash. If you want to delete elements serially then delete at the index 0 till the array is empty. So you've to delete 0 -> 0 -> 0 provided there are 3 elements in the array.

Frankenstein
  • 15,732
  • 4
  • 22
  • 47