Understanding the Navigation Stack

This morning I wrote about a bug in Corgi Corral that I’d been dealing with for a few months. The act of writing about it was apparently just what my brain needed in order to sort it out, and as it happens, it was a real rookie mistake! I’m hoping that by explaining the problem (and solution), I might help other beginners like me.

I started my previous post by explaining Corgi Corral’s navigation stack:

Main Menu –> Scene Selection –> GameViewController –> Score Summary

Basically, the game’s view controllers should always be in that order. From the main menu, you progress to a level selection screen, then to the game itself, and finally to a summary of your score. From there, you should only move backwards through the stack. In other words, the “retry level” button should pop the score summary off the stack and move back down to the game controller. The “choose a different level” button should pop two view controllers off the stack and go all the way back to the Scene Selection screen.

Here’s where I went wrong: in my Storyboard, on the Score Summary screen, I accidentally hooked up the “choose a different level” button to a “Show” segue instead of an “unwind” segue. This caused the following to happen:

Main Menu -> Scene Selection -> GameViewController -> Score Summary -> Scene Selection

In other words, a brand new “Scene Selection” controller was pushed onto the stack. The problem was compounded each time I selected a new level:

Main Menu -> Scene Selection -> GameViewController -> Score Summary -> Scene Selection -> GameViewController -> Score Summary -> Scene Selection -> GameViewController

You can see how after playing a few games, this got way out of hand. There were multiple GameViewControllers in existence that still had references to game scenes. The memory growth, however, was somehow still negligible despite all of these duplicates.

So how did I diagnose the problem? By using simple print debugging. In the viewWillAppear method of each view controller I printed out the entire navigation stack like so: print(navigationController.viewControllers). Then I watched the output as I played a few games. As soon as I saw new controllers being added to the stack, I knew I was in trouble.

The solution was to make sure I was using an unwind segue to move backwards through the stack after the user selected an option from the Score Summary screen.

I know, I know…dumbest mistake ever. But now at least I know that there will only ever be four view controllers in existence at one time in my app. I hope someone can learn from this!