Kyle Griffith Kyle Griffith - 1 month ago 11
Objective-C Question

multiple calls adding to navigation stack

I have three tab bar controllers. From those tab bar controllers there are buttons to go to different views. Some of those views are to other view controllers that are the same as the tab bar view controllers, some are not. These different views in turn can go to other views. In reality a user could go on forever allocating new views in this way. The three main views are NewsFeedVC ProfileVC and NotificationsVC. Then the secondary view include VotesListVC. The intended usage is that a user could select one of the three tabs and go on forever popping more view controllers on the stack. The user can either hit the navigation back button all the way to the original view, or hit another tab. Hitting the other tab should release the stack of view controllers on the previous stack; going back to the original tab will reveal the root view controller. The problem is my code has gotten outrageously ugly trying to determine which view controller was last. In this app, I have opted out of Storyboard so I have to do all the navigation myself. My question is, what is the proper way to know what is on the stack and how to remove it.
Here is some of the code that I am using.

//for when the user wants to leave an individual post allViewControllers is an array
NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray: self.navigationController.viewControllers];

-(void)backTapped{
if (_postKey) {
ActivityViewController *newVC = [allViewControllers objectAtIndex:1];
[allViewControllers insertObject:newVC atIndex:0];
[allViewControllers removeLastObject];
self.navigationController.viewControllers = allViewControllers;

CATransition* transition = [CATransition animation];
transition.duration = 0.2f;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromLeft;
[self.navigationController.view.layer addAnimation:transition
forKey:kCATransition];
[self.navigationController popViewControllerAnimated:NO];
}
}


//Here is how I handle leaving the profileVC, I have booleans determining what view it is from.

-(void)backTapped{

if (fromWorldFeed) {
WorldFeedViewController *newVC = [allViewControllers objectAtIndex:1];
newVC.retainTablePosition=true;
[allViewControllers insertObject:newVC atIndex:0];
[allViewControllers removeLastObject];
self.navigationController.viewControllers = allViewControllers;

[self.navigationController popViewControllerAnimated:NO];
}else if(_fromActivity){
ActivityViewController *newVC = [allViewControllers objectAtIndex:1];
[allViewControllers insertObject:newVC atIndex:0];
[allViewControllers removeLastObject];
self.navigationController.viewControllers = allViewControllers;
}else{
VotesListViewController *newVC =[allViewControllers objectAtIndex:1];
[allViewControllers insertObject:newVC atIndex:0];
[allViewControllers removeLastObject];
self.navigationController.viewControllers =allViewControllers;
}
CATransition* transition = [CATransition animation];
transition.duration = 0.2f;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromLeft;
[self.navigationController.view.layer addAnimation:transition
forKey:kCATransition];
[self.navigationController popViewControllerAnimated:NO];
}


I save the tab bar index when it loads as well to know if it changes and then I can somehow release the old tabs view stack.

-(void)setTabBarIndex{
NSInteger tabBarIndex =self.tabBarController.selectedIndex;
NSString *tabBarStr=[@(tabBarIndex) stringValue];
[[NSUserDefaults standardUserDefaults]setObject:tabBarStr forKey:@"tabBarIndex"];


}

This code would be fine if the user could only navigate to one or two views at most. However I have problems that are hard to account for when the user goes deep into the app.
Is there some kind of way I can have my app delegate manage this?

Answer

As you have mentioned, you have three tabs in your UITabBarController. So first take three UINavigationController. NewsFeedVC, ProfileVC and NotificationsVC will be the rootViewController s for those three UINavigationControllers.

newsFeedNavigationController = [[UINavigationController alloc] initWithRootViewController:yourNewsFeedVCObject];
profileNavigationController = [[UINavigationController alloc] initWithRootViewController:yourProfileVCObject];
notificationsNavigationController = [[UINavigationController alloc] initWithRootViewController:yourNotificationsVCObject];

yourTabBarController.viewControllers = @[newsFeedNavigationController, profileNavigationController, notificationsNavigationController];

Now, if you want to display any new view controller can just push the view controller, the respective navigation controller will handle the stack.

Suppose you have selected news feed tab, so current navigation controller is newsFeedNavigationController. Now you want to push a view controller, A, onto that. Just push the view controller A's object on that navigation controller. If you want to push a ProfileVC or NotificationVC's object on that navigation controller, please do that, you do not need to switch/update yourTabBarController.selectedIndex value. Because you have pushed ProfileVC or NotificationVC's object on newsFeedNavigationController and you are still on that navigation controller. This is normal behaviour of iOS app.

view controller's stack of newsFeedNavigationController, profileNavigationController and notificationsNavigationController will be different. Push/Pop will be executed on the navigation controllers as your need(Want to display a view controller-push, want to get back-pop). You do not have to mix them.

Comments