appfrosch
appfrosch

Reputation: 1356

Popping to specific ViewController in NavigationController stack

I have set up a NavigationController programmatically in my SceneDelegate. My app logic requires at a certain stage to go back to a specific ViewController on the stack. The problem is that when I do this with popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]?, I seem to loose track of the NavigationController – there is no Back button available even though I did not pop back to the root controller.

When I am in the ViewController in question, my NavigationController's ViewControllers' stack looks like this:

(lldb) po navigationController?.viewControllers
▿ Optional<Array<UIViewController>>
  ▿ some : 4 elements
    ▿ 0 : <Vocabulary.MainViewController: 0x7fbd4570dcd0>
    ▿ 1 : <Vocabulary.VocabularyViewController: 0x7fbd4566ce80>
    ▿ 2 : <Vocabulary.LearnViewController: 0x7fbd45532180>
    ▿ 3 : <Vocabulary.LearnResultViewController: 0x7fbd4569f900>

(lldb) po mainNavigationController.viewControllers
▿ 4 elements
  ▿ 0 : <Vocabulary.MainViewController: 0x7fbd4570dcd0>
  ▿ 1 : <Vocabulary.VocabularyViewController: 0x7fbd4566ce80>
  ▿ 2 : <Vocabulary.LearnViewController: 0x7fbd45532180>
  ▿ 3 : <Vocabulary.LearnResultViewController: 0x7fbd4569f900>

I now pop back to navigationController.viewControllers[1] in LearnResultViewController like so:

override func willMove(toParent parent: UIViewController?) {
        if let _ =  mainNavigationController.topViewController?.isKind(of: LearnResultViewController.self) {
            if isPresenting {
                if let vocabularyViewController = mainNavigationController.viewControllers.first(where: { $0 is VocabularyViewController} ) {
                    mainNavigationController.popToViewController(vocabularyViewController, animated: true)
                    //navigationController?.popToViewController(vocabularyViewController, animated: true) //same behavior
                }
            }
        }
    }

isPresenting is just a flag I set in LearnViewController in viewDidLoad cause willMove is called when entering LearnViewController already and obviously I only want to pop when leaving and mainNavigationController is a global variable right now (mainly cause I thought it should be global so that it can be referenced from anywhere which did not help so far...).

Now when I do hit the back button, I can get back to VocabularyViewController, but I don't have a Back button any more there – so the stack of my NavigationController seem to be lost.

While still in willMove I can see that LearnResultViewController.navigationController becomes nil – which causes my problem. Above mentioned mainNavigationController still has the state by then, but the "local" navigationController becomesnil:

(lldb) po mainNavigationController.viewControllers
▿ 2 elements
  ▿ 0 : <Vocabulary.MainViewController: 0x7fbd4570dcd0>
  ▿ 1 : <Vocabulary.VocabularyViewController: 0x7fbd4566ce80>

(lldb) po navigationController?.viewControllers
nil

(lldb) po navigationController
nil

What can I do to just get back to the desired ViewController while keeping my stack / state in my NavigationController? Is there another approach I should take?

To be quite frank I don't even understand why the scene's navigationController is set to nil in the first place...

Upvotes: 1

Views: 619

Answers (2)

Vladislav Markov
Vladislav Markov

Reputation: 587

I tried your approach, and it really doesn't work.

You should remove LearnViewController from your navigation stack in LearnResultViewController.

navigationController?.viewControllers.removeAll(where: { $0 is LearnViewController })

After that, when you hit the back button, you will get back to VocabularyViewController. And the back button will be there.

You shouldn't override willMove for that.

Upvotes: 1

Ananta Prasad
Ananta Prasad

Reputation: 3859

for swift 4.0

for controller in self.navigationController!.viewControllers as Array {
        if controller.isKind(of: DashboardVC.self) {
            _ =  self.navigationController!.popToViewController(controller, animated: true)
            break
        }
    }

for swift 3

let viewControllers: [UIViewController] = self.navigationController!.viewControllers
for aViewController in viewControllers {
    if aViewController is YourViewController {
        self.navigationController!.popToViewController(aViewController, animated: true)
    }
}

Upvotes: 1

Related Questions