1
votes

I've read many question about this issue but I don't figure out what it doesn't work.

Basically I want to change my root controller after the user logged in the or logout from the app. I am also using the storyboard. My problem is SILoginViewController dealloc's function is never called, in this controller I send Notification and the observer is not removed, so it mess up everything, and after several "login/logout" it receives several notifications.

My AppDelegate :

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
     [self.window setFrame:[[UIScreen mainScreen] bounds]];
     BOOL isLoggedIn = [[SIUser aUser] isLoggedIn];    // from your server response

     NSString *storyboardId = isLoggedIn ? @"rootViewController" : @"navVcForLogin";
     self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:storyboardId];


     return YES;
}

If the user was not logged in and he success the process a Notification is send, here is the handler where I want to change the rootViewController :

- (void)loginSuccessHandler:(id)sender
{  
      UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
      
      SIRootViewController * vc = [sb instantiateViewControllerWithIdentifier:@"rootViewController"];

      [UIApplication sharedApplication].keyWindow.rootViewController = vc;
}

This is the same process for the logout, and here is the notification's handler :

- (void)logoutHandler:(id)sender
{
      UIWindow *myWindow = [(SIAppDelegate *)[[UIApplication sharedApplication] delegate] window];

      SILoginViewController * vc = [sb instantiateViewControllerWithIdentifier:@"navVcForLogin"];
     
      [UIApplication sharedApplication].keyWindow.rootViewController = vc;
}

The easiest is to show you directly the storyboard :

Storyboard

The implementation in the Storyboard could seems weird but I'm using https://github.com/romaonthego/RESideMenu

I followed their storyboard implementation.

The thing is the SILoginViewController dealloc's method is never called.

But by the way it is working fine, in appearance I mean, when I run the application the behaviour is the good one, but It is sure it will mess out later on.

UPDATE

And I guess it is the common behaviour but there is no transition when the root view controller is changed and there is a black screen for a really short time when the new controller is appearing.

Black screen resolved using : in my AppDelegate.m

- (void)changeRootViewController:(UIViewController*)newRootViewController
{
    if (!self.window.rootViewController) {
        self.window.rootViewController = newRootViewController;
        return;
    }

    UIView *snapShot = [self.window snapshotViewAfterScreenUpdates:YES];
    [newRootViewController.view addSubview:snapShot];
    self.window.rootViewController = newRootViewController;
    [UIView animateWithDuration:0.3 animations:^{
        snapShot.layer.opacity = 0;
        snapShot.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
    } completion:^(BOOL finished) {
        [snapShot removeFromSuperview];
    }];
}

RootViewController Switch Transition Animation

This probably kind of a duplicate question but I spent hours to figure out this problem.

1
Lookup transitionViewController on the Google machine. That is how I would do this. Transition the rootViewController to the new one. There are a few other calls necessary to make it work and they should get your dealloc called. - Doug Watkins
I tried the solution of this answer : stackoverflow.com/questions/7703806/… , which resolves my transition issue, but not the problem about deallocating SILoginViewController. - BoilingLime
The solution you found doesn't seem to implement the other methods. I'll repost them when I get to my computer. - Doug Watkins
Ok thank you very much. - BoilingLime
I added an answer with all of the code I meant for you to find. Including the missing methods that your half solution didn't implement. - Doug Watkins

1 Answers

2
votes
[currentRootViewController willMoveToParentViewController:nil];         // notify the VC of movements

[self addChildViewController:newRootViewController];        //Add the new VC

[self transitionFromViewController: currentRootViewController toViewController: newRootViewController
                          duration: 0.15 options:UIViewAnimationOptionCurveEaseInOut
                        animations:^{
                            newRootViewController.view.frame = currentRootViewController.view.frame;
                        }
                        completion:^(BOOL finished) {       //Cleanup from the move
                            [currentRootViewController removeFromParentViewController];
                            [newRootViewController didMoveToParentViewController:self];
                        }];

The code for willMoveToParentViewController and didMoveToParentViewController will notify the ViewController of the changes, and should get your dealloc called, since there is now nothing holding onto the ViewController, unless you have a pointer to it somewhere, then you will need to nullify all your pointers to the code. The solution you tried is only half of what needs to go on to get the transition completed successfully.