I made a practice app where the main view is a simple list. When the item of the list is tapped, it presents the detail view. Inside the detail view is a “textField” to change the items title.
I always have the error by making this steps:
When you delete the item that you changed the name, the app will crash and presente me the following error: “Fatal error: Index out of range in SwiftUI”
How can I fix it?
The main view:
struct ContentView: View {
@EnvironmentObject var store: CPStore
var body: some View {
NavigationView {
VStack {
List {
ForEach(0..<store.items.count, id:\.self) { index in
NavigationLink(destination: Detail(index: index)) {
VStack {
Text(self.store.items[index].title)
}
}
}
.onDelete(perform: remove)
}
Spacer()
Button(action: {
self.add()
}) {
ZStack {
Circle()
.frame(width: 87, height: 87)
}
}
}
.navigationBarTitle("Practice")
.navigationBarItems(trailing: EditButton())
}
}
func remove(at offsets: IndexSet) {
withAnimation {
store.items.remove(atOffsets: offsets)
}
}
func add() {
withAnimation {
store.items.append(CPModel(title: "Item \(store.items.count + 1)"))
}
}
}
The detail view:
struct Detail: View {
@EnvironmentObject var store: CPStore
let index: Int
var body: some View {
VStack {
//Error is here
TextField("Recording", text: $store.items[index].title)
}
}
}
The model:
struct CPModel: Identifiable {
var id = UUID()
var title: String
}
And view model:
class CPStore: ObservableObject {
@Published var items = [CPModel]()
}
Instead of getting the number of items in an array and using that index to get items from your array of objects, you can get each item in the foreach instead. In your content view, change your For each to this
ForEach(store.items, id:\.self) { item in
NavigationLink(destination: Detail(item: item)) {
VStack {
Text(item.title)
}
}
}
And Change your detail view to this:
struct Detail: View {
@EnvironmentObject var store: CPStore
@State var item: CPModel
var body: some View {
VStack {
//Error is here
TextField("Recording", text: $item.title)
}
}
}