Description
We have a sidebar-detail layout in our app. Since we moved from NavigationView
on iOS 15 to NavigationSplitView
on iOS 16, we've seen some issues.
- On iOS 16, the app is always killed, or reset, when the app enters background. That means whatever the sidebar and detail view show, they will almost always return to the initial blank screen state when coming back from background.
- On iOS 17, the background issue is mitigated. However, the toolbar button is missing after coming back from background.
Those problem aren't present in NavigationView
on iOS 15.
Steps to Repro
General steps…
- Create a new iOS app demo project with deployment target min version set to iOS 16.
- Copy and paste the code snippet below into ContentView.swift.
- Run the app on iPad simulator with the respective Simulator OS versions.
iOS 16
- Tap the info button on the side bar, it presents a "form sheet" style page.
- Put the app into background.
- Open any app. I opened the Photos app.
- Switch back to the demo app. The sheet is dismissed and the app returns to the initial state, which indicates the app was reset in the background.
- When I tap the info button again, it doesn't present a sheet.
iOS 17
- Same steps as 1-3 above for iOS 16.
- Switch back to the test app. The sheet is not dismissed, which means the app wasn't reset in the background.
- However, you can see the info button is missing from the sidebar's top toolbar.
Similar Posts
- NavigationSplitView resetting when app enters background: https://developer.apple.com/forums/thread/733472
- Selection state is lost when navigating to/from home screen: https://developer.apple.com/forums/thread/728657
- SwiftUI NavigationSplitView looses toolbar button when App moves to background - iOS 17 / Xcode 15.0: https://stackoverflow.com/questions/77253055
Repro Code Snippet
import SwiftUI
struct ContentView: View {
let samples = ["foo", "bar"]
var body: some View {
NavigationSplitView {
NavigationStack {
sidebar
}
} detail: {
NavigationStack {
detail
}
}
}
var sidebar: some View {
Sidebar(samples: samples)
}
var detail: some View {
Text("Select a sample from the list.")
}
}
struct Sidebar: View {
@State private var isPresented = false
let samples: [String]
var body: some View {
List {
ForEach(samples, id: \.self) { sample in
Text(sample)
}
}
.navigationTitle("Foo")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Info") {
isPresented = true
}
.sheet(isPresented: $isPresented) {
AboutView()
}
}
}
}
}
struct AboutView: View {
@Environment(\.dismiss) private var dismiss: DismissAction
var body: some View {
NavigationStack {
List {
Text("Copyright © 2023 Foo. All Rights Reserved.")
}
.navigationTitle("About")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button("Done") {
dismiss()
}
}
}
}
}
}