3

We are using SwiftUI with a NavigationView.

We have one view (ParentView) that updates its data asynchronously through its view model (ParentViewModel) and then re-renders its body according to the new data. When the completion block is called after we have entered the second view (ChildView) through the NavigationLink, problems occur, e.g. the app automatically navigating back to the first view without any user interaction, or missing completion block calls in the second view.

struct ParentView: View {

    @ObservedObject private var viewModel = ProjectListViewModel()

    var body: some View {
        ForEach(viewModel.items) { item in
            NavigationLink(destination: ChildView(item: item)) {
                Text(item.label)
            }
        }.onAppear(perform: viewModel.loadData))
    }
}

class ParentViewModel: ObservableObject {

    @Published var items: [Item] = []

    func loadData() {
        loadDataAsynchronously { [weak self] newItems in
            // Problems occur if this completion block is called after we have entered ChildView
            self?.items = newItems
        }
    }
}

class Item: Identifiable { ... }

This error occurs on the simulator as well as on a physical device.

  • Check if id of the item being visible in ChildView remains the same. – Asperi Apr 07 '21 at 10:26
  • The ids of the Items should remain the same as they forward to the PFObject.objectId which is a unique database identifier from the Parse Server SDK. – Philipp Fahlteich Apr 07 '21 at 10:29
  • 1
    You should change `@ObservedObject` to `@StateObject` – LuLuGaGa Apr 07 '21 at 12:10
  • @LuLuGaGa StateObject behaves similarly to the EnvironmentObject as it is instantiated as a Singleton, isn't it? Sadly this does not fix the error and is only possible on view models without parameters. – Philipp Fahlteich Apr 07 '21 at 16:02
  • It is not a singleton. StateObject is like State, and ObservedObject is like Binding so the View where it is initialised needs StateObject to show that it is the owner of it and it should be persisted. What happens in your case when the view model gets updated the view gets recreated and new copy of view model is initialised, StateObject would prevent it from happening. – LuLuGaGa Apr 07 '21 at 16:13
  • @LuLuGaGa Thank you very much for the explanation! I have tried replacing ObservedObject with StateObject but it does not support parameters and is therefore not applicable for some of our use cases - and where it was, it did not fix the described bug. Furthermore we think that the ObservedObject leads to a re-rendering of the View but not to a re-instantiation, so the ViewModel stays the same. We have now replaced the NavigationView with [a library](https://github.com/matteopuc/swiftui-navigation-stack) which works for us, but we are still curious whether this behavior can be fixed. – Philipp Fahlteich Apr 08 '21 at 11:11
  • Can you try having one NavigationLink and having a state property ex. isActive. When user selects your Text, update that id/item in your view model like selectedItem and set isActive to true. – user832 Apr 15 '21 at 17:06

0 Answers0