简体   繁体   中英

ViewController Stack

So I am having an issue with my apps logic in whether or not, based on a user's credentials, the main view of my app should display a tableview over the main view after the login view has been dismissed or just display the main view after the login view has been dismissed.

So currently, I send an http post request to a server where I get a token back and then make another call after that to get the amount of list items the user has, lets say games.

If the user only has ONE game, I want the main view to be displayed, but if the user has multiple games, then the user should see a tableview, press on one of the cells then modally dismiss the tableview to show the mainview.

Typically I have these 3 controllers, at least this is the way I'm thinking about how the implementation should be, not sure if its the correct way.

So assume that controller A is the login, controller B is the tableview, and controller C is the mainview.

Controller C is in the bottom of the stack, whereas controller A is at the top. But potentially, controller B may or may not be displayed based on the information from controller A. When I say bottom of the stack, I mean if the user isn't already logged in, then the login view (controller A) will be presented without animation over the mainview (controller C). So technically, the main view(controller C) is always loaded but data has not been fed to it, only after the login view has been dismissed by correctly submitted credentials.

Here are a few methods implented in the mainviewcontroller (controller C) to check if the user has logged in, if they haven't then the app technically goes through the mainviewcontroller first then presents the login view. I understand that this is the way to go for login schemas with app development but I am not 100%:

- (void)showLoginViewAnimated:(BOOL)animated {
    NSLog(@"[MainViewController] Show login view controller");
    PowerOneLoginTabBar *loginVC = [[PowerOneLoginTabBar alloc] init];
    [self presentViewController:loginVC animated:NO completion:nil];
}

- (void)logoutHandler:(NSNotification *)notification {
    NSLog(@"[MainViewController] Logout handler");
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"userLoggedIn"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    [self showLoginViewAnimated:YES];
}

In viewdidLoad of the mainview (viewcontroller C):

 BOOL isUserLoggedIn = [[NSUserDefaults standardUserDefaults] boolForKey:@"userLoggedIn"];
    if( !isUserLoggedIn || (!setAuthenticationKey || [setAuthenticationKey isKindOfClass:[NSNull class]]))
        [self showLoginViewAnimated:NO];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logoutHandler:) name:LOGOUT_NOTIFICATION object:self.view];

Here's my login handler implemented in the login viewcontroller (controller A):

- (void)authenticateHandler:(NSNotification *)notification {
    NSLog(@"[LoginViewController] Authenticate handler");

    NSDictionary *userDict = [notification userInfo];



    BOOL isUserAuthenticated =
    //[username isEqualToString:[userDict objectForKey:@"username"]] &&
    //[password isEqualToString:[userDict objectForKey:@"password"]] &&
    [api_Key isEqualToString:[userDict objectForKey:@"apiKey"]] &&
    ([_auth isEqualToString:[userDict objectForKey:@"authKey"]]);

    [[NSUserDefaults standardUserDefaults] setBool:isUserAuthenticated forKey:@"userLoggedIn"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    if( isUserAuthenticated ){

        NSLog(@"Authentificated");
        [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];

    } else {
        NSLog(@"Not Authentificated");
        [self showAlert];
    }
}

And in the viewDidLoad method of the loginview (viewcontroller A):

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(authenticateHandler:) name:AUTHENTICATE_NOTIFICATION object:self];

If you guys could give me a sort of schema or fool-proof theory in how this is possible to do that would be great.

Because at the moment, I currently dismiss the login view with the mainview shown but then I present the tableview modally (animated), which is not desireable. So you can imagine one view being dismissed through animation then for a second you see the mainview, then the tableview is presented over the mainview through animation. I don't want the user to even see the mainview until they've logged in AND after he selects a game to view details for UNLESS the user has just one game!

And remember the only reason why the tableview is shown in between view A and C is because the user might have more than 1 game, but if they just have 1 game then go from controller A to controller C, instead of controller A to controller B to controller C.

I'm not sure I fully understand the issue, but here's some advice that I hope is useful:

A UINavigationController is especially well suited for a stack of vcs, especially, it seems to me, in the case you present.

The main vc can check the user's logged in state and either present the login vc or not. It can begin by assuming the user has more than one game to choose from and build the vc stack as follows:

- (void)viewDidAppear:(BOOL)animated {

    // notice I moved the logical or to make the BOOL more meaningful
    BOOL isUserLoggedIn = [[NSUserDefaults standardUserDefaults] boolForKey:@"userLoggedIn"] || (!setAuthenticationKey || [setAuthenticationKey isKindOfClass:[NSNull class]]);

    if (!isUserLoggedIn) {
        SelectGameVC *selectGameVC = // not sure how you build this, either alloc-init or get from storyboard
        // notice animation==NO, we're putting this on the stack but not presenting it
        [self.navigationController pushViewController:selectGameVC animated:NO];
        LoginVC *loginVC =  // alloc or use UIStoryboard instantiateViewControllerWithIdentifier
        // we push this one with animation, user will see it first
        [self.navigationController pushViewController:loginVC animated:YES];
    }
}

When the loginVC completes login, it can ask the question, does user have more than one games? If more than one, pop back just one vc to reveal the SelectGame vc we stacked underneath, otherwise pop all the way back.

// LoginVC.m

// login successful
if (loggedInUser.games.count > 1) {
    // it's underneath us, remember?  we pushed it before we got here
    [self.navigationController popViewControllerAnimated:YES];
} else {
    // it's underneath us, but we don't need it, pop all the way back
    [self.navigationController popToRootViewControllerAnimated:YES];
}

Incidentally, Your NSLog made me smile to think of my old friend who used to say "authentificated" rather than "authenticated".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM