Skip to content

Instantly share code, notes, and snippets.

@mbrandonw
Last active May 21, 2020 16:51
Show Gist options
  • Select an option

  • Save mbrandonw/6affc2803d38d3514d12790d0666593a to your computer and use it in GitHub Desktop.

Select an option

Save mbrandonw/6affc2803d38d3514d12790d0666593a to your computer and use it in GitHub Desktop.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment