onAppear is called when the view hasn't appeared

I'm using a 100% SwiftUI app, currently on Xcode 12 Beta 4

In my ContentView, I have a simple TabView

Code Block swift
struct ContentView: View {
var body: some View {
TabView {
AgendaView()
.tabItem {
Image(systemName: "list.bullet")
Text("Agenda")
}
HealthView()
.tabItem {
Image(systemName: "heart")
Text("Health")
}
}
}
}


The AgendaView and HealthView have onAppear methods. On App launch, the AgendaView is the one visible, but onAppear is called for both AgendaView and HealthView.

Why is that? Shouldn't onAppear be called only when the view actually appears on screen?

Code for HealthView and AgendaView

Code Block swift
struct AgendaView: View {
var body: some View {
VStack {
Text("Hello, AgendaView!")
}.onAppear{
print("AgendaView.onAppear")
}.onDisappear(){
print("AgendaView.onDisappear")
}
}
}
struct HealthView: View {
var body: some View {
VStack {
Text("Hello, HealthView!")
}.onAppear{
print("HealthView.onAppear")
}.onDisappear(){
print("HealthView.onDisappear")
}
}
}




As an update, this issue seems to only appear on device.

In the simulator of iOS 14, it works fine.
Further information
  • This only appears on actual devices, in the simulator, the issue does not appear.

  • The issue only appears with projects created with the SwiftUI App Life Cycle. The issue does not appear in projects with the UI Kit App Delegate Life Cycle projects.

I submitted a feedback: FB8285799

You can recreate this issue by creating a new project, choosing SwiftUI App from the Life Cycle dropdown, and replacing your ContentView with the following code.

If anyone has any thoughts on a workaround I'd appreciate it!

Code Block swift
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
AgendaView()
.tabItem {
Image(systemName: "list.bullet")
Text("Agenda")
}
HealthView()
.tabItem {
Image(systemName: "heart")
Text("Health")
}
SettingsView()
.tabItem {
Image(systemName: "gear")
Text("Settings")
}
}
}
}
struct AgendaView: View {
var body: some View {
VStack {
Text("Hello, AgendaView!")
}.onAppear{
print("AgendaView.onAppear")
}.onDisappear(){
print("AgendaView.onDisappear")
}
}
}
struct HealthView: View {
var body: some View {
VStack {
Text("Hello, HealthView!")
}.onAppear{
print("HealthView.onAppear")
}.onDisappear(){
print("HealthView.onDisappear")
}
}
}
struct SettingsView: View {
var body: some View {
VStack {
Text("Hello, SettingsView!")
}.onAppear{
print("SettingsView.onAppear")
}.onDisappear(){
print("SettingsView.onDisappear")
}
}
}


If it only appears on device then it is important to know what version of iOS your device is running. I can reproduce a similar problem on iOS 14b8 is that what you tried?

My Feedback is FB8689302
A TabView’s tab onAppear is erroneously called when the tab disappears when another is selected

And I referenced your feedback which sometimes helps get it resolved quicker.
Seeing this issue in the iOS14 release version as well.
Just for the record, I am experiencing this issue as well. I have a simple TabView:

Code Block
import SwiftUI
struct HomeTabbedView: View {
    var body: some View {
        TabView {
            RehearsalsView()
                .tabItem {
                    Image(systemName: "calendar.circle.fill")
                    Text("Rehearsals")
                }
            ProfileWrapperView()
                .tabItem {
                    Image(systemName: "person.crop.circle.fill")
                    Text("User Profile")
                }
        }
    }
}


The ProfileWrapperView consists of the following:

Code Block
import SwiftUI
struct ProfileWrapperView: View {
    @EnvironmentObject var portal: Portal
    @State var draftAdult: Adult = Adult.default
    
    var body: some View {
        if (portal.adult) != nil {
            ProfileEditView(adult: $draftAdult)
                .onAppear {
                    self.draftAdult = self.portal.adult!
                    print("ProfileEditView appearing")
                }
                .onDisappear {
                    self.portal.adult! = self.draftAdult
                    print("ProfileEditView disappearing")
                }
        } else {
            Text("No adult data found.")
        }
    }
}


When the user switches tabs from the User Profile tab to the Rehearsals tab, the onDisappear handler is called (expected) immediately followed by the onAppear handler (unexpected). I'm looking into submitting a bug report now. (This will be my first time doing this, so wish me luck. :) If anyone has a workaround for this, please let me know.
Still experiencing this issue. Really hope they fix this.
This has been fixed with Xcode 12.1.1

onAppear now only is called, wenn the tab actually was selected.
This is an issue again with Xcode 12.2 and iOS 14.2 when using TabView with PageTabViewStyle.

.onAppear is called multiple times on the first tab, but only once after scrolling pages.
Can confirm, Xcode 12.2 and iOS 14.2 this bug appears. Also: the selection from TabView(selection: $XYZ) is updated after onAppear is called. Though this only happens on the first tab.
Any progress here? Is this fixed?
Any update about this issue?
Any update about this issue?
Still... Xcode 12.5 on an application with UI Kit App Delegate Life Cycle and iOS 13 as a target. tested in multiple devices and simulators.
Agreed. Still broke. Can this be fixed please?

I am seeing the same issue with Xcode 12.4 + Deployment target macOS 10.15

I am seeing this issue too on: iOS 14.6 Xcode 12.5 macOS 11.4

Xcode 12.5.1, iOS 14.5: the bug is there for me too

Any chance of this being fixed apple?

.onAppear and .onDisappear just don't run for me in Xcode 13 beta 5. If I remove the TabView and have a single page then they work fine.

Any update about this issue?

Seems the bug is fixed in Xcode 13.2 beta (13C5066c) and iOS 15.2.

In my app I use three tabs. My app starts with tab 0. If I go to tab 1, the on onAppear-Method gets called. Last, I go to tab 2 but the onAppear-Method gets called twice. But the method should only called once.

I managed to work it around by adding viewDidAppear callback to SwiftUI, and replacing onAppear callbacks with it.

The code: https://gist.github.com/alongotv/7f450e8c47ed3f057e1f6d35443af269

Usage: apply onDidAppear modifier instead of onAppear to those views you use in TabView.

A rough example:

struct RootView: View {
    @State var selection: Int = 1

    var body: some View {
        TabView(selection: $selection) {
            FirstTabView().tag(1)
            SecondTabView().tag(2)
        }
    }
}

struct FirstTabView: View {

    var body: some View {
        Text("first tab view")
            .onDidAppear {
                // load data
            }
    }
}

struct SecondTabView: View {

    var body: some View {
        Text("second tab view")
            .onDidAppear {
                // load data
            }
    }
}

Hope this helps.

Problems are still there, XCode 12.5 & iOS 14.5 simulator

Issue is still there in XCode 13.2.1 on simulator iOS 15.0.

I'm experimenting this issue in Xcode 14.2 and iOS 16.2...

.onAppear {
      withAnimation(.easeOut(duration: 0.5)) {
        print("IS ANIMATING: \(isAnimating)")
        isAnimating = true
      }
    }
TabView {
      ForEach(0..<5) { item in 
        FruitCardView()
      } //: FOREACH
    } //: TABVIEW
    .tabViewStyle(PageTabViewStyle())
    .padding(.vertical, 20)

That onAppear is for a ZStack. And this is the logs that prove onAppear is called before the item is visible in the TabView...

onAppear is called when the view hasn't appeared
 
 
Q