Hi everyone, this is my first post. I'm facing an issue that I don't fully understand. The problem started once I migrated to use NavigationStack instead of navigation View.
I have a View, let's called "NextWeekView" where I do some async process onAppear, calling an async function from the "NextWeekViewModel". Depending on the result of this processing, I need to navigate automatically to different Views. I use @Published variables on the ViewModel that I populate with the destination view. Once the processing is finish, on the View and still on onAppear, I enable a @State navigate, and return the destination View based on the @Publish:
The View
enum DestinationType { case play case menu case endseason } struct NextWeekView: View { @ObservedObject var team: Team @StateObject var nextWeekViewModel = NextWeekViewModel() @State private var destination: DestinationType? = nil @State var navigate: Bool = false var body: some View { LoadingScreenView(text: self.nextWeekViewModel.currentStep) .navigationDestination(isPresented: self.$navigate) { destinationView(for: self.nextWeekViewModel.destination) } .navigationBarHidden(true) .statusBar(hidden: true) .onAppear{ Task { await nextWeekViewModel.processNextWeek(team: team) if nextWeekViewModel.finishedProcessing { self.navigate.toggle() } print("navigate to: \(self.navigation)") // debug, it always print the expected value. } } } // Function to return the appropriate view based on the destination @ViewBuilder private func destinationView(for destination: DestinationType?) -> some View { switch destination { case .play: MatchPlayView(team: self.team) case .menu: GameMenuView().environmentObject(team) case .endseason: SeasonEndView().environmentObject(team) case .none: EmptyView() } } }
The ViewModel
class NextWeekViewModel: ObservableObject { var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext let backgroundContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) @Published var currentStep:LocalizedStringKey = "" @Published var destination: DestinationType? = .menu @Published var finishedProcessing: Bool = false @MainActor func processNextWeek(team: Team) async { .... if currentWeek.matchdays.filter({ md in return md.num > currentWeek.current_matchday }).count == 0 { await self.endWeekProcess() // We check if it is end of season if currentSeason.current_week == currentSeason.weeks.count && currentWeek.matchdays.filter({ md in return md.num > currentWeek.current_matchday }).count == 0 { // End of season await self.endSeasonProcess(team: team, currentSeason: currentSeason) self.destination = .endseason // WORKS } else { // We go next week self.currentStep = "Create cash operations" await self.createCashOperations(team: team, week: currentSeason.current_week) self.currentStep = "Create messages" await self.createMessages(team: team) self.destination = .menu //WORKS } } else { print("Ther are more matchdays, lets pass the matchday") // THIS DOES NOT WORK // Any Modifications of destination is reflected on the view, but automatic navigation is not taking place self.destination = .play //self.destination = .menu // this also do not work. } self.finishedProcessing = true }
What's happens: The code works when app goes through code path marked as //WORKS but not when follows code path //DO NOT WORK. Interestingly, it works perfectly on iOS 18. But not in iOS16/iOS17.
If I add an interactive NavigationLink instead of the navigationDestination in the View :
if self.nextWeekViewModel.finishedProcessing { NavigationLink(destination:destinationView(for: self.nextWeekViewModel.destination)){ SimpleButtonWithIconView(icon: "chevron.right.2", text: "Next") .padding(.bottom, 10) } }
Then it works as expected but I really want to avoid the user to tap Next for a seamlessly gameplay
I've tried all combinations of state variables, using different state variables per destination, but I always arrive to the same situation.
I also printed everything left and right and View values looks consistent so I think the ViewModel is doing the right thing (also with the NavigationLink it works). It's simply that the "automatic" navigation does not want to navigate in certain occasions.
I'm completely out of ideas. Any feedback will be welcomed. Otherwise I will revert back to NavigationView.
Thank you in advance!