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])
}
}
Post
Replies
Boosts
Views
Activity
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.
Looks like the error localizedDescription is incorrect. I have the same issue, and when looking into the LAError header, I see that the code -4 is type "systemCancel".
I got that error when I had a bug in my code leading to me initiating two or more simultaneous biometrics prompts. Fixed by making sure only one biometrics-authentication was running.