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...
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.
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
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

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")
}

Create issue, thanks UIKit))

Code Block
struct UIKitAppear: UIViewControllerRepresentable {
    let action: () -> Void
    func makeUIViewController(context: Context) -> UIAppearViewController {
       let vc = UIAppearViewController()
        vc.action = action
        return vc
    }
    func updateUIViewController(_ controller: UIAppearViewController, context: Context) {
    }
}
class UIAppearViewController: UIViewController {
    var action: () -> Void = {}
    override func viewDidLoad() {
        view.addSubview(UILabel())
    }
    override func viewDidAppear(_ animated: Bool) {
        action()
    }
}
public extension View {
    func uiKitOnAppear(_ perform: @escaping () -> Void) -> some View {
        self.background(UIKitAppear(action: perform))
    }
}


Example:

Code Block
var body: some View {
SomeView().uiKitOnAppear {
print("I am uiKitAppear")
}
}

Any Update here?
I can't seem to find an acceptable workaround.

I am using xCode 12.2 and am still experiencing this issue
This issue happens in Xcode Version 12.2 (12B45b) and iOS 14.2. Is there any workaround for this issue?
Echoing everyone else: This issue is still painfully present, and there's no known workaround. Something needs to happen. This is not okay.
Found a weird quirk. When you pass in the method directly (line 9/10) it's a lot more stable.

Code Block swift
.onAppear {
viewModel.onAppear()
}
.onDisappear {
viewModel.onDisappear()
}
.onAppear(perform: viewModel.onAppear)
.onDisappear(perform: viewModel.onDisappear)


Just found out that it works correctly on iOS 14 if you have parentheses after onAppear/onDisappear:

Code Block Swift
.onAppear() {
print("...code here")
}
.onDisappear() {
print("...code here")
}


Is there any update? I cannot believe that this is not working. Is there a new way of using these lifecycle methods?
Hi Guys, I don't have a nativ fix for this problem but a workaround I have found after 3 days of research which I have posted here: https://stackoverflow.com/a/65857640/6131259 I hope it helps some of you.
On Xcode 12.3 / iOS 14.3 and onAppear is still very flaky. I'm actively avoiding it at all costs everywhere and calling functions manually while constructing the view instead.
Only relamquad's answer with UIKit gave me the most confidence and it works. With the flakiness from version to version for SwiftUI's onAppear, just a simple syntax change and everything stops working, relying solely on SwiftUI is too risky. I can't believe this is not high on the bug list. onAppear is such an essential part
iOS 14 .onAppear() is called on DISappear instead of appear
 
 
Q