View controller retaining another when changing rootViewController

590 Views Asked by At

I've found a memory leak in an app where the following is done:

Imagine two view controllers, each of which calls a function in the appDelegate similar to this:

func switchRootViewController() {    
    let vc = getTheOtherViewController()
    self.window?.rootViewController = vc
}

So far this is working well - the other VC is shown and the one that called the function is deallocated.

But when you present a third view controller from first or second VC via: present(ThirdViewController(), animated: true)

And then call the above function in the appDelegate from ThirdVC (to show viewController one or two by making it the rootViewController), this ThirdVC and the VC that presented it do not get deallocated.

Any idea why that is?

Can post sample project if needed. VC's are instantiated from storyboard if that makes any difference.

1

There are 1 best solutions below

2
On BEST ANSWER

You are messing up the view hierarchy here. You should dismiss all the presented view controllers of the current rootViewController before switching to the new one. This is the only solution I've found to work!

Your switchRootViewController method should be like below,

func switchRootViewController() {    
   if var topController = UIApplication.shared.keyWindow?.rootViewController {
        while let presentedViewController = topController.presentedViewController {
            topController = presentedViewController
        }
        topController.dismiss(animated: true, completion: {
            let vc = getTheOtherViewController()
            self.window?.rootViewController = vc
        })
    }
}

If you there are multiple view controllers presented,

func switchRootViewController() {   
   self.view.window!.rootViewController?.dismiss(animated: true, completion: {
      let vc = getTheOtherViewController()
      self.window?.rootViewController = vc
   })    
}