`NavigationSplitView` with `ZStack` in detail view causes `.sheet(item` to hang

I have a problem with a MacCatalyst app I build and run on MacOS 14.6 with XCode 16.4. The problem doesn't occur on MacOS 13.6 or iOS 16 or 17. In this app if I click a button to show a .sheet(item a few times (typically between 3 and 8 times) then the app starts consuming 100% CPU and the Spinning Wait Cursor shows. The cause of the issue is that my NavigationSplitView has a ZStack so that state is maintained for all panels, as recommended here1 and here2. Minimum reproducible example is below. I would appreciate any suggestions on how to address this. This app must support iOS 16 and MacOS 13.6 as well. Thank you!

import SwiftUI

enum Panel: Hashable {
    case panel
}    

@main
struct MyApp: App {
    @State private var selection: Panel? = Panel.panel

    var body: some Scene {
        WindowGroup {
            NavigationSplitView {
                List(selection: $selection) {
                    NavigationLink(value: Panel.panel) {
                        Label("Panel", systemImage: "circle")
                    }
                }
            } detail: {
                ZStack { // this causes a crash on MacOS 14.6, but is required to maintain state on 13.6
                    ContentView()
                }
            }
        }
    }
}

struct PopupItem: Identifiable {
    let id = UUID()
}

struct ContentView: View {
    @State var popupItem : PopupItem?
    
    var body: some View {
        Button {
            popupItem = PopupItem()
        } label: {
            Text("Show popup")
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .navigationBarTitleDisplayMode(.inline)
        .sheet(item: $popupItem) { popupItem in
            DismissView()
        }
    }
}

struct DismissView: View {
    @Environment(\.dismiss) var dismiss
    var body: some View {
        NavigationStack {
            Button {
                dismiss()
            } label: {
                Text("Dismiss")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .principal) {
                    Text("Popup")
                }
            }
        }
    }
}
Answered by DTS Engineer in 799778022

@JbXyz A few suggestions

  • Are you able to reproduce this using the latest beta?

ZStack { // this causes a crash on MacOS 14.6, but is required to maintain state on 13.6 ContentView() }

Could you clarify which state doesn't get preserved on 13.6? because here is the best to drive behavior directly with the selection variable:

  var body: some View {
        NavigationSplitView {
            List(selection: $selection) {
                NavigationLink(item.id, value: item.id)
            }
        } detail: {
           if let selection {
              selection.destination
           } else { 
             Text("Make a selection") 
           }
        }
    }
  }

Can't you use an if #available to handle this?

@JbXyz A few suggestions

  • Are you able to reproduce this using the latest beta?

ZStack { // this causes a crash on MacOS 14.6, but is required to maintain state on 13.6 ContentView() }

Could you clarify which state doesn't get preserved on 13.6? because here is the best to drive behavior directly with the selection variable:

  var body: some View {
        NavigationSplitView {
            List(selection: $selection) {
                NavigationLink(item.id, value: item.id)
            }
        } detail: {
           if let selection {
              selection.destination
           } else { 
             Text("Make a selection") 
           }
        }
    }
  }

Thank you @DTS Engineer . Here is an example from the WWDC session "What's new with SwiftUI". It isn't a great experience, because when the user switches between menu items state of the detail view is recreated. Scroll position, textfield values, and @State in FoodOverview() or MusicOverview() are lost. This challenge is in all SwiftUI versions, not just MacOS 13.6. The workaround I use is to wrap the detail view in a ZStack. The problem on MacOS 13.6 is using ZStack makes .sheet buggy. I haven't tried the beta - I need to solve on 13.6.

  @State var selectedTask: PartyTask?
  var body: some View {
        NavigationSplitView {
           List(PartyTask.allCases, selection: $selectedTask) {
              NavigationLink(value: $0) {
                 TaskLabel(task: $0)
              }
            }
        } detail: {
           switch selectedTask {
              case .food:
                  FoodOverview()
              case .music:
                 MusicOverview()
           }
        }
    }
 }
`NavigationSplitView` with `ZStack` in detail view causes `.sheet(item` to hang
 
 
Q