Post

Replies

Boosts

Views

Activity

Reply to SwiftUI Navigation Stack pops back on ObservableObject update
I ran into the same issue, which seems to be because when a dataupdate is published from an ObservableObject, the view listening for it will re-render, and therefore tear down the viewstack that sits on top of it. It would be nice to have an apple-provided pause/resume publish functionality of the ObservableObject in order to allow a view down in the viewstack to update its datasource in the background without tearing down the viewstack on top of it. I have not found such functionality, but implemented something that so far handles it quite nicely. This is particularly relevant when you have views that is built upon several datasources, so that one part of the view is ready for further interaction and navigation while other parts of the view is still loading, and I do not want wherever I navigated to to pop just because another part of the parent-view datasources finished loading. The way I handled it was: In my ObservableObject, I removed the @Published keyword for the variables in question in order to avoid the auto-publishing of updates. In addition I added a private "visible" var, and functions for onAppear and onDisappear which sets the visibility variable accordingly. Whenever my data should be loaded/updated, I check the visibility variable in order to determine if changes are to be published. If yes, then call objectWillChange.send() which will publish that there is a change in the observable object, and prepare the view owning the observable to fetch new data from it. Now, in that view, I added .onAppear and .onDisappear, where I call the onAppear and onDisappear of the observable. In the onAppear of the ObservableObject, I also call the objectWillChange.send() in order to trigger a publish of the data inside. With this approach, I am able to allow an ObservableObject to refresh its datasource in the background while another view is pushed on top of it without popping the viewstack when data is loaded. But as soon as the view in question once again becomes visible, it will be populated with fresh data.
Apr ’21
Reply to SwiftUI Navigation Stack pops back on ObservableObject update
Update: Made a small extention that so far looks to be handling it. Not thoroughly tested though, so might need some rework. But the general idea is Extend ObservableObject language class PausableObservableObject: ObservableObject { private var isPaused: Bool = false private var hasPendingUpdates = false var onResume: (() - ())? = nil func publishWillUpdate() { if (!isPaused) { self.objectWillChange.send() } else { hasPendingUpdates = true } } func pause() { isPaused = true } func resume() { isPaused = false if hasPendingUpdates { hasPendingUpdates = false self.objectWillChange.send() } onResume?() } } And make a viewModifier that is visibility aware: language struct VisibilityAwareObservables: ViewModifier { let observables: [PausableObservableObject] func body(content: Content) - some View { AnyView(content) .onAppear { for observable in observables { observable.resume() } } .onDisappear { for observable in observables { observable.pause() } } } } extension View { func visibilityAwareObservables(observables: [PausableObservableObject]) - some View { ModifiedContent(content: self, modifier: VisibilityAwareObservables(observables: observables)) } } Now make your observableObject an instance of PausableObservableObject and make sure that whenever data to be published is changed, you call language publishWillUpdate() and simply pass this object along with any other PausableObservableObject into the viewModifier visibilityAwareObservables Example: language struct ExampleView: View { @ObservedObject var datasource = MyDatasourceObservable() /* MyDatasourceObservable extends PausableObservableObject */ var body: some View { VStack(alignment: .leading, spacing: 8) { Text(datasource.somePublishedParameter) } .visibilityAwareObservables(observables: [datasource]) } }
Apr ’21