2

I am developing an application using Storyboards. This application requires the user to be logged in.

The Storyboard has a Login View as initial. When login is ok, it performs a segue to a TabViewController.

On any call to the API, I check if the server returns 401 (not-authorized). If this happens, a boolean is set to false (boolean isLogged). AppDelegate observes this boolean. If value is changed to false, I want to return the user to the login screen (remember, the initial view on Storyboard).

Here is some code:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

if ([keyPath isEqualToString:@"isLogged"]) {
    BOOL logged = [[change objectForKey:NSKeyValueChangeNewKey] boolValue];
    if (logged) {
        NSLog(@"Logged in succesfully!");
    } else {
        NSLog(@"Logout performed");

        [self.window makeKeyAndVisible];
        [self.window layoutSubviews];

    }

}

This works fine, but when I try to login again LoginOK segue is not performed.

I have tried many other options, something like this:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];

UIViewController *loginController = [storyboard instantiateViewControllerWithIdentifier:@"Login"];

[source presentModalViewController:loginController animated:YES];

But the problem is that I don't know which View Controller performed the logout. Source has to be the current View Controller shown in the application, isn't it?

Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
Daniel Albert
  • 757
  • 5
  • 22

2 Answers2

3

I thought I'd share this rather random idea with you.

What if you didn't make the login screen an essential step in your view hierarchy, but present it modally from any of your normal view controllers as soon as app state needs logging in. That's what modal view controllers are there for - not letting the user resume the normal flow until some explicit prerequisite has been met.

By doing it this way you don't have to worry about unwinding the whole navigation stack to the initial controller. It's much easier to preserve the state as well, since as soon as the authentication is successfully performed user should be able to resume her normal workflow, not start over.

Just an idea.

Update #1:

One option is to use a custom notification to carry the login is required state. You'd have to make all your view controllers observe the notification and the one that is currently visible will perform the presenting of modal view controller.

You can use this code borrowed from here to check if a view controller instance is visible:

if (viewController.isViewLoaded && viewController.view.window) {
    // viewController is visible
}
Community
  • 1
  • 1
svena
  • 2,769
  • 20
  • 25
  • Yes, maybe you're right, but it does not actually answers my question. How can I know from the AppDelegate which view is shown to call presentModalViewController method? Maybe is another way to do what I want. – Daniel Albert Jul 01 '12 at 21:50
  • I found a similar approach here: http://stackoverflow.com/questions/7913840/login-screen-with-storyboarding-possible but I cannot figure what is source in this code. – Daniel Albert Jul 01 '12 at 21:51
  • I made an update (#1) to address your question in comment above. – svena Jul 02 '12 at 06:11
  • This is a good idea. In hindsight, I should've built my app with this structure – Andrew Oct 29 '12 at 21:47
3

Finally I solved the problem changing the observer for isLogged from App Delegate to my custom TabViewController. In viewDidLoad I subscribe to this var.

In method observeValueForKeyPath I do the following:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];

LoginViewController *loginController = [storyboard instantiateViewControllerWithIdentifier:@"Login"];


[self presentModalViewController:loginController animated:YES];
Daniel Albert
  • 757
  • 5
  • 22
  • How do you dismiss your login view ? I get `Warning: Attempt to dismiss from view controller while a presentation or dismiss is in progress!` error :( – expert Sep 04 '13 at 01:46
  • What I do now is replace rootViewController with loginViewController. So: self.view.window.rootViewController = [self.view.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:@"LoginView"]; – Daniel Albert Sep 09 '13 at 18:34