Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIWindow setRootViewController not clearing existing hierarchy

In my app I programmatically change root view controllers based on user actions e.g. login/logout functionality.

In iOS 8 - I'm noticing a strange issue. Even after setting rootViewController on the window, the old hierarchy still persists. I just verified it by capturing view hierarchy.

- (void) logout{
     [self.window setRootViewController:[self loadLoginView]];
}

-(UIViewController *) loadLoginView{
      WelcomeScreenVC *wsVC;
      wsVC = [[WelcomeScreenVC alloc] initWithNibName:@"WelcomeScreenVC" bundle:nil];
      UINavigationController *onboardingVC = [[UINavigationController alloc]initWithRootViewController:wsVC];
      return onboardingVC;
 }

Even after executing this line of code, the old logged in view hierarchy still persists. Would appreciate if anybody can suggest what's happening behind the scenes.

Edit: I just looked at UIWindow setRootViewController documentation and here's what Apple has to say about it:

The root view controller provides the content view of the window. Assigning a view controller to this property (either programmatically or using Interface Builder) installs the view controller’s view as the content view of the window. If the window has an existing view hierarchy, the old views are removed before the new ones are installed.

like image 373
Naz Mir Avatar asked Nov 07 '14 07:11

Naz Mir


2 Answers

I have noticed the very same thing.

Basically, I have a fairly complicated storyboard that acts as a login/welcome interface. This interface sits in a navigation controller, which presents another navigation controller modally.

After a certain point, the user takes an action that transitions him to the main interface. Using the iOS 8 view debugger I noticed that the old view hierarchy was still around after setting the rootViewController property of the window.

My solution, for now is to use the following code, right before I re-assing the window.rootViewController property:

for (UIView* subView in self.window.rootViewController.view.subviews) {
    [subView removeFromSuperview];
}
[self.window.rootViewController.view removeFromSuperview];

It ain't pretty, but it works.

Another odd thing I noticed is that the welcome interface's modally presented viewController is not properly cleaned up using this method. I have to manually dismiss it AND do this clean up.

like image 200
TMart Avatar answered Nov 15 '22 08:11

TMart


The best way to fix is:

self.window.subviews.forEach { $0.removeFromSuperview() }

or, in old style:

for view in self.window.subviews {
   view.removeFromSuperview()
}
like image 39
KostiaZzz Avatar answered Nov 15 '22 07:11

KostiaZzz