I have created an ObservableObject in a View.
@ObservedObject var selectionModel = FilterSelectionModel()
I put a breakpoint inside the FilterSelectionModel
's init
function and it is called multiple times. Because this View is part of a NavigationLink
, I understand that it gets created then and along with it, the selectionModel. When I navigate to the View, the selectionModel is created again.
In this same View I have a "sub View" where I pass the selectionModel as an EnvironmentObject
so the sub-view can change it.
AddFilterScreen().environmentObject(self.selectionModel)
When the sub view is dismissed, the selectionModel is once more created and the changes made to it have disappeared.
Interesting Note: At the very top level is a NavigationView
. IF I add
.navigationViewStyle(StackNavigationViewStyle())
to this NavigationView
, my selectionModel's changes disappear. BUT if I do not add the navigationStyle
, the selectionModel's changes made in the sub view remain!! (But I don't want a split nav view, I want a stacked nav view)
In both cases - with or without the navigationStyle
, the selectionModel is created multiple times. I can't wrap my head around how any of this is supposed to work reliably.
Latest SwiftUI updates have brought solution to this problem. (iOS 14 onwards)
@StateObject
is what we should use instead of @ObservedObject
, but only where that object is created and not everywhere in the sub-views where we are passing the same object.
For eg-
class User: ObservableObject {
var name = "mohit"
}
struct ContentView: View {
@StateObject var user = User()
var body: some View {
VStack {
Text("name: \(user.name)")
NameCount(user: self.user)
}
}
}
struct NameCount: View {
@ObservedObject var user
var body: some View {
Text("count: \(user.name.count)")
}
}
In the above example, only the view responsible (ContentView) for creating that object is annotating the User
object with @StateObject
and all other views (NameCount) that share the object is using @ObservedObject
.
By this approach whenever your parent view(ContentView) is re-created, the User
object will not be re-created and it will persist its @State, while your child views just observing
to the same User
object doesn't have to care about its re-creation.