Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444

I'm trying to present the items of an array in multiline text by looping over them in a ForEach. I need them to be able to be deleted, reordered and edited.

I'm getting the index out of range error when I try to delete any of the items, and it's getting thrown in the AppDelegate (I tried stepping through to see where it was). If I replace the TextEditor with a regular text field I can delete without issue (TextField also crashes). It seems like the loop is throwing the error instead of updating the array?

I can pass in the text as a constant and it doesn't crash, but then I can't edit it.

Here is a simplified version of my code that I created to troubleshoot the issue.

struct ContentView: View {
  @State private var editMode: EditMode = .active
  @State var array = ["one", "two", "three", "four"]
   
  var body: some View {
       
      List{
        ForEach (0..<array.count, id: \.self) { index in
          //Text(array[index])
          //TextField("", text: array[$0])
          TextEditor(text: $array[index])
        }
        .onDelete { indexSet in
          let removeIndex = Int(Array(indexSet).first!)
          array.remove(at: removeIndex)
        }
      }
    }
}

I created another View that takes in the unbound value and displays it in a TextEditor, but I feel like that's not a good solution. I am new to Swift, so maybe I'm missing something simple? Is this how I should be creating this screen to do what I want in SwiftUI? Thanks!
Post not yet marked as solved Up vote post of PetePan Down vote post of PetePan
6.7k views

Replies

Please try this:
Code Block
struct ContentView: View {
@State private var editMode: EditMode = .active
@State var array = ["one", "two", "three", "four"]
@State var arrayIndices: [Int] = Array(0..<4)
var body: some View {
List{
ForEach(arrayIndices, id: \.self) { index in //<- ForEach `arrayIndices`
TextEditor(text: $array[index])
}
.onDelete { indexSet in
arrayIndices.remove(atOffsets: indexSet) //<- Modify `arrayIndices`
}
}
}
}

When you show a List with ForEach(someCollection, id: \.someProperty), you need to remove elements from someCollection in onDelete.
(More specifically, the id values need to be consistent before and after onDelete.)

That does work as far as the display goes, but unfortunately I need the data in the array to be updated as well (the string array I'm looking to delete from is stored in Core Data, so I want to update the database when changes are made).

 I need the data in the array to be updated as well

Have you really tried my code?
The strings in array are updated by user input. You just need to manage deleted entries.

The strings in array are updated by user input. You just need to manage deleted entries.

Sorry I meant updated in general, I want to update the array when the user makes any change: editing, reordering, adding or removing elements. For that to work I'd have to track deletes somehow and think about how that might be impacted by inserts and reordering as well, which seems messy and introduces lots of potential problems.

I found a thread on Stack Overflow which I think is closer to what I was hoping for, and so far appears to be working.
Code Block
ForEach (0..<array.count, id: \.self) { index in
          TextEditor(text: Binding(  // << use proxy binding !!
                get: { array[index] },
                set: { array[index] = $0 }))
        }
        .onDelete { indexSet in
           array.remove(atOffsets: indexSet)
        }



Add a Comment