7
votes

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.

3
Can you share the code for [self loadLoginView] please?Josh Heald
@JoshHeald added it to the questionNaz Mir
Is that copied out of your app directly, or did you type it? I ask because the loadLoginView declares a void return type, which wouldn't be helping mattersJosh Heald
@JoshHeald, sorry I copied it from the app, but removed some sensitive info while editing. The return type of that method is UIViewControllerNaz Mir
no problem. I'm struggling to recreate this, but wanted to know how you're checking the hierarchy - you say you "verified it by capturing view hierarchy", is this using the new Xcode 6 View Hierarchy Debugger, or some other means?Josh Heald

3 Answers

2
votes

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.

1
votes

The best way to fix is:

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

or, in old style:

for view in self.window.subviews {
   view.removeFromSuperview()
}
0
votes
var loginNavigationController: OnBoardViewController?{
    willSet{
        if newValue == nil {
            loginNavigationController?.view.removeFromSuperview()
        }
    }
}

loginNavigationController = nil Then set window.rootviewcontroller = {Different VC}