Search code examples
swiftxcodeswiftui-navigationlinkswiftui

ObervableObject being init multiple time, and not refreshing my view


I have a structure like this:

contentView {
    navigationView {
        foreach {
            NavigationLink(ViewA(id: id))
        }
    }
}
/// where ViewA contains an request trigger when it appears
struct ViewA: View {

    @State var filterString: String = ""

    var id: String!
    @ObservedObject var model: ListObj = ListObj()

    init(id: String) {
        self.id = id
    }

    var body: some View {
        VStack {
            SearchBarView(searchText: $filterString)
            List {
                ForEach(model.items.filter({ filterString.isEmpty || $0.id.contains(filterString) || $0.name.contains(filterString)  }), id: \.id) { item in
                    NavigationLink(destination: ViewB(id: item.id)) {
                        VStack {
                            Text("\(item.name) ")
                        }
                    }
                }
            }

        }
        .onAppear {
            self.model.getListObj(id: self.id) //api request, fill data and call objectWillChange.send()
        }
    }
}

ViewB has the same code as ViewA: It receives an id, stores and requests an API to collect data.

But the viewB list is not being refreshed.

I also noticed that viewB's model property

@ObservedObject var model: model = model()

was instantiated multiple times.

Debugging, I found that every navigationLink instantiates its destination even before it is triggered. That's not a problem usually, but in my case i feel like the ViewB model is being instantiated 2 times, and my onAppear call the wrong one, reason why self.objectWillChange.send() not refreshing my view.


Solution

  • If your @ObservedObject is being initialized multiple times, it is because the owner of the object is refreshed and recreated every time it has state changes. Try to use @StateObject if your app is iOS 14 and above. It prevents the object from being recreated when the view refreshes. https://developer.apple.com/documentation/swiftui/stateobject

    When a view creates its own @ObservedObject instance it is recreated every time a view is discarded and redrawn. On the contrary a @State variable will keep its value when a view is redrawn. A @StateObject is a combination of @ObservedObject and @State - the instance of the ViewModel will be kept and reused even after a view is discarded and redrawn

    What is the difference between ObservedObject and StateObject in SwiftUI