iOS 14 .onAppear() is called on DISappear instead of appear

I've got a View with
Code Block
.onAppear(perform: {
print("appear")
})
.onDisappear(perform: {
print("disappear")
})
set on it.

In iOS 13.5, when I navigate away from the view via a NavigationLink, it prints "disapear"; when I close the new view and get back to the first view "appear" gets printed. All as it should be.

Now in iOS 14, this happens instead:
  • when the view is first shown, it prints "appear"

  • when navigating away from the view, it prints "disappear" and "appear"

  • when navigating back to the view, nothing gets printed

  • when navigating away from the view, then "appear" gets printed, along with the expected "disappear"

...is this some new super-lazy way of doing things or just plain a bug?

It runs havoc with my login, as I set @Binding vars in the second view, which are evaluated back in the first view when .onAppear() runs. Worked great until iOS 14...
Post not yet marked as solved Up vote post of Emnasut Down vote post of Emnasut
19k views

Replies

Can confirm this issue. Started to appear in beta 2.
So is there any way around that?

It's especially annoying, as changes to an object using @Binding and @State in a child view doesn't seem to update the UI anymore - the value changes correctly but it's not reflected in the UI. Just like with .onAppear() the UI gets updated on navigating away and back again on the second time.

Now with .onAppear() not working correctly my UI always lags behind one step...
Our app has also been affected by this strange behavior of onAppear since 14 beta 1.
(Others have reported similar case: https://developer.apple.com/forums/thread/652257 )

Our first view reads the QR code from camera and opens second view.
Since the read QR code data needs to be reset when back from second view, the initialization process of first view is set to be triggered when the view is (re)appeared.
The current behavior of onAppear is serious problem because the initialization process of first view invalidates the content of second view.

AFAIK until beta 2, first view's onAppear was triggered when back from second view.
As it was gone in beta 3, we may need to observe visibility of first view in background or to workaround some other way.

Apple says "work reliably" in beta 3, but we still hope onAppear behave as it names.
Post not yet marked as solved Up vote reply of bola Down vote reply of bola
I can confirm the same issue in Xcode 12, beta 4. To be clear, the issue only exists when running the app in iOS 14. Works fine in below iOS versions.
Can confirm that this is still an issue in beta 6.
Same behaviour on iOS 14 beta 8. OnAppear gets called after navigating via NavigationLink to a different view, which of course messes up the apps behavior
Update:

I think I found a solution! (At least until the bug itself gets fixed) ->

Try to add a second "OnAppear" modifier somewhere below the one you actually want.

Code Block swift
VStack{
...
}
.onAppear(){
print("Works as usual - only fired on appear, even when navigation back to this view as expected")
}
.onAppear(){
print("Fired directly after onDisappear")
}
.onDisappear(){
print("Fired on Disappear as expected")
}


It seems like the second onAppear modifier always gets fired shortly after onDisappear, as reported here. If your add another onAppear modifier somewhere above, it will behaves initially expected!

So this may be a workaround until the bug is fixed, maybe it even helps in finding the cause of the problem.

If it doesn't work for you, try putting the second onAppear above the one you want, instead of below. In my tests one or the other seemed to work.

If this also doesnt work, try placing the second on Appear somewhere else in your view and debug/experient with which gets fired. For me usually one behaves correctly while the other one show the strange behaviour.

I guess it may be some parsing error of the swift document or its timing based problems which may be cause by how many States/Bindings you are referencing in the specific block.


Update 2: -> above solution doesnt seem to work as I initially thought

Further testing seems to point me towards the conclusion, that it's the code inside the onAppear, that leads to the behavior. Adding a second onAppear somewhere with a simple print works as expected, while my onAppear always shows the incorrect behavior regardless of where I place it. So something inside the onAppear, maybe the amount of code, or some specific references cause the problem
  • This works correctly!!! Thank you. Please note that in my environment,

    VStack{ ... } .onAppear(){ print("Fired directly after onDisappear") } .onAppear(){ print("Works as usual - only fired on appear, even when navigation back to this view as expected") } .onDisappear(){ print("Fired on Disappear as expected") }

    works!

Add a Comment
Also a problem with TabView and onAppear on iOS 14b8
FB8689302 A TabView’s tab onAppear is erroneously called when the tab disappears when another is selected

Post not yet marked as solved Up vote reply of malc Down vote reply of malc
Error still persists in iOS14 GM. :(
I have the same problem with my custom toast view. The App is basically unusable. Although I have figured that this bug is not always present. Still persists in iOS 14.2 Beta 1
I am facing this bug in one of my apps, which works perfectly on iOS 13 but showing problem on iOS 14. I am supper annoyed. For last 2 days, it gives me a real headache.
I also have this problem in the official version of iOS 14 and xcode 12. The onAppear will not be called when TabView is switched. This problem is quite serious.
Can confirm this is still an issue on iOS 14.0.1 - iOS 14.2.. Hopefully Apple fixes this
Still broken in iOS 14.1.

Actually it looks like it's broken in a different way though. I think it's behaving as expected except opening popovers, sheets, and alerts causes onAppear of the parent view to get called, but only the first time a popover, sheet, or alert is opened. Super weird behavior.
iOS 14.2 (18B5083a)

It works:
Code Block
.onAppear {
print("onAppear")
}


But this is not:
Code Block
.onAppear {
isNavigationBarHidden = true // any logic
print("onAppear")
}

Post not yet marked as solved Up vote reply of xc85 Down vote reply of xc85