views:

47

answers:

1

I have an app with a TabBar.

One of the TabBar-connected views is actually variable:

Upon first opening of that view, it shall show a login dialog. If the user logs in, the login view is finished and the actual data view is shown.

Later, if the user goes back to this tab, the data view shall appear right away, so no more login dialog view.

Until now, I've solved this by directly manipulating the tab bar item's navigation controller's view controller array: Initially, it is set to show the login view. Once the user has logged in, the login controller is removed from the navigation controller and the actual data view is inserted instead.

I am not happy with this solution, though, as it causes problems once there are more than 5 tab items.

Hence, I wonder how I can avoid this navigation controller "patching" and instead have a new root controller for this tab that will then either invoke the login view or immediately show the data view.

Note: There are design reasons why the data view can't just pop up a modal view controller for the login. Therefore, I really like to provide something like a proxy controller that can direct the functionality to one of two other controllers of its choice.

How would I accomplish that?

Or are there other concepts I employ use here?

A: 

My suggestion would be to have two completely separate view controllers. Once login is complete, change the tab bar's view controller array by removing the login view controller and adding the content view controller. Something like this:

- (void) didLogin {
    UITabBarController *tabBarController = self.tabBarController;
    NSMutableArray *array = [NSMutableArray arrayWithARray:tabBarController.viewControllers];
    int idx = [array indexOfObject:self];
    UIViewController *contentViewController = //Create or get a chached copy of the content view controller
    //Optionally here you could copy the tab bar item rather than setting it up within the contentViewController.
    contentViewController.tabBarItem = self.tabBarItem;
    [array replaceObjectAtIndex:idx withObject:contentViewController];
    tabBarController.viewControllers = array;
    tabBarController.selectedViewController = contentViewController;
}

Edit:

If you're within the More view controller, it automatically detects if it's showing a navigation controller when choosing a tab normally. If you're doing it programmatically, I think you'd just have to do the same thing, but manually. Something like this:

- (void) didLogin {
    UITabBarController *tabBarController = self.tabBarController;
    NSMutableArray *array = [NSMutableArray arrayWithARray:tabBarController.viewControllers];
    if (array.count > 5 && [array indexOfObject:self] >= 5) {
        [tabBarController popToRootViewControllerAnimated:NO];
        [tabBarController.moreNavigationController pushViewController:contentViewController animated:NO];
        //Note: Not sure if this next line should be contentViewController or moreNavigationController.
        tabBarController.selectedViewController = contentViewController;
    } else {
        //Normal method above
    }
}
Ed Marty
Thanks for making the effort, Ed, but I am using currently exactly what you propose, and I thought I had explained that. Apparently not too well.This technique is not usable to me because it won't work any more once one moves the particular tab item into the "More" area (only when you have more than 5 tab items). Unless I did something else wrong.Have you successfully used your code with > 5 tab items, where this tab lives inside the More area?
Thomas Tempelmann
Added another option
Ed Marty
Ed, I'll give you the green checkmark for trying to help me. It's not what I can use, and I eventually went the opposite way by having one controller which switches its view. This requires that the controller handles both functionality in the same class, but it looks functionally cleaner to me than messing with the tab bar's pre-assigned controllers.
Thomas Tempelmann