The following code sample demonstrates a nested data structure in SwiftUI. You can add rows, drill down into those rows, and then add rows to that child node.
If you drill down 2 levels deep, then tapping “Add row” button no longer updates the UI. But, if you drill out and then drill back in you will see that the rows have appeared.
Paste the following code in a SwiftUI preview to demonstrate:
import SwiftUI
struct NestedState: Equatable, Identifiable {
var children: [NestedState] = []
let id: UUID
var description: String = ""
}
class Store: ObservableObject {
@Published var state: NestedState
init(state: NestedState = NestedState(id: UUID())) {
self.state = state
}
}
struct ContentView: View {
@ObservedObject var store: Store
var body: some View {
NavigationView {
NestedStateView(state: self.$store.state)
}
}
}
struct NestedStateView: View {
@Binding var state: NestedState
var body: some View {
Form {
Section(header: Text("Hi")) {
ForEach(
Array(self.state.children.enumerated()),
id: \.element.id
) { index, child in
HStack {
TextField(
"Untitled",
text: self.$state.children[index].description
)
Spacer()
NavigationLink(
destination: NestedStateView(state: self.$state.children[index])
) {
Text("")
}
}
}
}
}
.navigationBarTitle(self.state.description.isEmpty ? "Untitled" : self.state.description)
.navigationBarItems(
trailing: Button("Add row") {
self.state.children.append(NestedState(id: UUID()))
}
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(store: Store())
}
}If you change the @ObservedObject var store: Store to be just a @State var store = NestedState(id: UUID()) it will begin working again. So it seems to have something to do with deriving bindings off of ObservableObjects.