NavigationSplitView freezes

DESCRIPTION OF PROBLEM

I have changed my app to the @Observable-Macro. When using an iPhone (on simulator and on real device) the navigation from a player to the player detail view and back breaks. In the attached video on my GitHub you can see me tapping on both players in the team, but the navigation ist not showing the detail view.

What is the reason? Is my usage/understanding of @Observable wrong? Is it wrong to have the selectedPlayer within the PlayerController which is @Observable? And why does it sometimes work and sometimes not?

The project can be found here: GitHub Project

STEPS TO REPRODUCE

  1. Start the App, add one or two demo teams, tap on a team and add two or more demo players.

  2. tap a player and then go back, tap the player again and back again. After a while (number of taps is always different), the navigation breaks. See my video attached.

PLATFORM AND VERSION

iOS Development environment: Xcode 15.4, macOS 14.5 (23F79) Run-time configuration: iOS 17.5,

Answered by SwiftyJoe in 802163022

It appears that the list selection does not reliably reset to nil when tapping the “back” button.

List(selection: $teamController.selectedTeam) {.....}

To address this, I added an onAppear modifier to force the list selection to reset to nil.

List(selection: $teamController.selectedTeam) {.....}
.onAppear {teamController.seletedTeam = nil}

This resolved the issue for both the team and player lists.

However, it would be helpful if someone could explain why the list selection doesn’t automatically reset to nil when tapping the back button.

@SwiftyJoe Thanks for providing the project.

  • Have identified where in their code issues are occurring.?
  • Could you share the steps you have taken to debug the issue?
  • Have you tried testing by replacing your data layer from CoreData to in-memory object to narrow down the cause of the issue ?

Please identify and share the troubleshooting and debugging steps you’ve taken to identify and resolve the issue. This would be an ideal starting point in debugging the issue you're experiencing. Thanks

@DTS Engineer Thanks for your answer.

To debug the issue I tried 2 different things:

FIRST: I changed the code from @State/@Observable back to @StateObject/ObservableObject today.

Instead of implementing the teamController as @State var teamController = TeamController() I used @StateObject var teamController = TeamController().

And instead of using @Observable class TeamController { var selectedTeam: Team? } I used class TeamController: ObservableObject{ @Published var selectedTeam: Team? }

Having the code like this, everything works fine and the NavigationSplitView does not freeze.

SECOND: Back-Button does not reset the teamController.selectedTeam to nil when using @State/@Observable

When tapping a team in the list-View, the tapped team will be set as teamController.selectedTeam. When tapping the back-Button after tapping a team, teamController.selectedTeam will not be set back to nil when my code uses @State/@Observable.

Conclusion

Depending on the usage of @State/@Observable or @StateObject/ObservableObject the NavigationSplitView seems to reset teamController.selectedTeam to nil or not. In my understanding of the @Obersvable-Macro it should make no difference? Am I using the @ObservableMacro wrong?

Today I removed code step by step to give you a more simpler project for the support and in addition tried to find which code may cause the problem. And I found the following:

The code is back to @State and @Observable.

In the file "TeamAndPlayerView.swift" I changed

detail: {
            if playerController.selectedPlayer != nil {
                PlayerDetailView(teamController: teamController, playerController: playerController, selectedPlayer: playerController.selectedPlayer!)
            } else {
                ContentUnavailableView("No Player", systemImage: "person.fill", description: Text("Please add or select a player to see the details."))
            }

into

detail: {
           EmptyView()
        }

Having the code like this, everything works fine and you can tap a team, go back again and tap the team again as often as you want. The teamController.selectedTeam is set back to nil correctly.

When implementing EmptyView() within the if clause, the NavigationSplitView sometimes freezes when repeatedly tapping into a team and then going back.

detail: {
            if playerController.selectedPlayer != nil {
                EmptyView()
            } else {
                ContentUnavailableView("No Player", systemImage: "person.fill", description: Text("Please add or select a player to see the details."))
            }
        }

Note: I was unable to create a more minimalistic code example because the error appears to be somewhere in the detail section.

Accepted Answer

It appears that the list selection does not reliably reset to nil when tapping the “back” button.

List(selection: $teamController.selectedTeam) {.....}

To address this, I added an onAppear modifier to force the list selection to reset to nil.

List(selection: $teamController.selectedTeam) {.....}
.onAppear {teamController.seletedTeam = nil}

This resolved the issue for both the team and player lists.

However, it would be helpful if someone could explain why the list selection doesn’t automatically reset to nil when tapping the back button.

NavigationSplitView freezes
 
 
Q