I tried as much as I could before asking the next "Index out of Range" question, because generally I understand why an index out of range issue occurs, but this specific issues makes me crazy:
struct Parent: Identifiable {
let id = UUID()
let name: String
var children: [Child]?
}
struct Child: Identifiable {
let id = UUID()
let name: String
var puppets: [Puppet]?
}
struct Puppet: Identifiable {
let id = UUID()
let name: String
}
class AppState: ObservableObject {
@Published var parents: [Parent]
init() {
self.parents = [
Parent(name: "Foo", children: [Child(name: "bar", puppets: [Puppet(name: "Tom")])]),
Parent(name: "FooBar", children: [Child(name: "foo", puppets: nil)]),
Parent(name: "FooBar", children: nil)
]
}
}
struct ContentView: View {
@EnvironmentObject var appState: AppState
var body: some View {
NavigationView {
VStack {
List {
ForEach (appState.parents.indices, id: \.self) { parentIndex in
NavigationLink (destination: ChildrenView(parentIndex: parentIndex).environmentObject(self.appState)) {
Text(self.appState.parents[parentIndex].name)
}
}
.onDelete(perform: deleteItem)
}
Button(action: {
self.appState.parents.append(Parent(name: "Test", children: nil))
}) {
Text("Add")
}
.padding(.bottom, 15)
}
.navigationBarTitle(Text("Parents"))
}
}
private func deleteItem(at indexSet: IndexSet) {
self.appState.parents.remove(atOffsets: indexSet)
}
}
struct ChildrenView: View {
@EnvironmentObject var appState: AppState
var parentIndex: Int
var body: some View {
let children = appState.parents[parentIndex].children
return VStack {
List {
if (children?.indices != nil) {
ForEach (children!.indices, id: \.self) { childIndex in
NavigationLink (destination: PuppetsView(parentIndex: self.parentIndex, childIndex: childIndex).environmentObject(self.appState)) {
Text(children![childIndex].name)
}
}
.onDelete(perform: deleteItem)
}
}
Button(action: {
var children = self.appState.parents[self.parentIndex].children
if (children != nil) {
children?.append(Child(name: "Teest"))
} else {
children = [Child(name: "Teest")]
}
}) {
Text("Add")
}
.padding(.bottom, 15)
}
.navigationBarTitle(Text("Children"))
}
private func deleteItem(at indexSet: IndexSet) {
if (self.appState.parents[self.parentIndex].children != nil) {
self.appState.parents[self.parentIndex].children!.remove(atOffsets: indexSet)
}
}
}
struct PuppetsView: View {
@EnvironmentObject var appState: AppState
var parentIndex: Int
var childIndex: Int
var body: some View {
let child = appState.parents[parentIndex].children?[childIndex]
return VStack {
List {
if (child != nil && child!.puppets?.indices != nil) {
ForEach (child!.puppets!.indices, id: \.self) { puppetIndex in
Text(self.appState.parents[self.parentIndex].children![self.childIndex].puppets![puppetIndex].name)
}
.onDelete(perform: deleteItem)
}
}
Button(action: {
var puppets = self.appState.parents[self.parentIndex].children![self.childIndex].puppets
if (puppets != nil) {
puppets!.append(Puppet(name: "Teest"))
} else {
puppets = [Puppet(name: "Teest")]
}
}) {
Text("Add")
}
.padding(.bottom, 15)
}
.navigationBarTitle(Text("Puppets"))
}
private func deleteItem(at indexSet: IndexSet) {
if (self.appState.parents[self.parentIndex].children != nil) {
self.appState.parents[self.parentIndex].children![self.childIndex].puppets!.remove(atOffsets: indexSet)
}
}
}
I can remove both children of Foo and FooBar without issues, but when I remove the Puppet of child bar first, then the app crashes like shown in the comments.
I unterstand that the childIndex doesn't exist anymore, but I don't understand why the view gets built again when there is no child with puppets.