View Full Version : UINavigationController and UITabBarController app issue

Jan 9, 2011, 03:21 AM

I'm new to the iPhone programming world and I have an app that I've been trying to get to work for a week with no success. I wish I could be articulate and ask my question without including code, but I can't do it. (I also hate looking at other people's code in threads...).

I'm trying to build an app that includes a UITabBarController and a UINavigationController. I have seen examples on how to get this working in Interface Builder, but I want to do it programatically. I have created a Tab Bar Application and in MainWindow.xib I correctly hooked up 5 View Controllers.

In my ClientAppDelegate.h file, I have:
IBOutlet UIWindow *window;
IBOutlet UITabBarController *rootController;
IBOutlet UINavigationController *navController;
//navController = [[UINavigationController alloc] init];
//navController = [[UINavigationController alloc] initWithNibName:@"WizardView" bundle:nil];
[window addSubview:rootController.view];

My second View Controller (WizardViewController) has the following code:
ClientAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
UINavigationController *navController = delegate.navController;
[self.view addSubview:navController.view];
[super viewDidLoad];

I created a separate nib file (WizardView.xib) which contains the following:
1. File's owner - hooked up to WizardViewController
2. view - connected to WizardViewController's view
3. a NavigationController whose class type is WizardNavigationController
4. a ClientAppDelegate, whose navController is hooked up to the NavigationController

In my WizardNavigationController (derived from UITableViewController), I have code which populates the table view:
NSUInteger row = [indexPath row];
AddressViewController *addressViewController = [[AddressViewController alloc] initWithNibName:@"AddressView" bundle:nil];
ClientAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
UINavigationController *navController = delegate.navController;
[navController pushViewController:addressViewController animated:YES];
[addressViewController release];

The problem is that when I click the second tab (WizardView), it doesn't load the WizardNavigationController which I clearly add it as a subview to WizardView. It does display a half-drawn NavigationController in the view, but I don't think that is the WizardNavigationController. And I don't think I'm loading the NavigationController correctly in the ClientAppDelegate and hooking it up properly in WizardView.xib. Because I needed access to the ClientAppDelegate's navController outlet, I had to add an object from the Library which I changed its class to ClientAppDelegate (kind of what happens in MainApplication.xib). I don't know if this is correct. Also, am I supposed to initialize navController in ClientAppDelegate's applicationDidFinishLaunching()? Can you tell what I'm doing wrong?


Jan 9, 2011, 04:59 PM
Just started few hours ago a project that has tab bar and navigation bars inside each of the tabs. The thing is, I am doing it all in InterfaceBuilder and I started with the window based app template so I can't really check everything now by creating a new project from scrath just to do it all in code, but...

In IB I am adding first the tab bar controller, then in each section I add nav controller and then I set the root view ontroller for each nav controller.

So, I think that you first need to initialize several nav controllers with their root views and then add each nav controller to each tab item and then add the tab controllers view as a subview to your main window.

The code that adds nav controllers view to your WizardViewControllers view seems wrong. Maybe someone else could help you more.

Jan 9, 2011, 08:59 PM
What about an easy question: if I don't have my Navigation Controller defined in the App Delegate, then how can I get a reference to it from other classes? Because when I have to push a new view in didSelectRowAtIndexPath(), I would have to do something like:

ClientAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.navController pushViewController:someController];

What if my navController is defined in SomeOtherViewController?


PS. Thanks for the tip idelovski

Jan 9, 2011, 09:10 PM
I think something like this in your "appDidFinishLoading" is probably what you are looking for.. I fought with this a bunch in the beginning:

//Standard tabBarControlller
tabBarController = [[UITabBarController alloc] init];

//Custom View controller, nothing special. Loads from NIB
QuoteViewController *quoteController = [[QuoteViewController alloc] initWithNibName:@"QuoteView" bundle:[NSBundle mainBundle]];

//Custom ViewController, nothing special
BookmarkViewController *bookmarkController = [[BookmarkViewController alloc] initWithTabBar];

//Standard navigation controller. Put the BookmarkView controller on it
UINavigationController *bookmarkNavController = [[[UINavigationController alloc] initWithRootViewController:bookmarkController] autorelease];

//Set the view controllers to the tabBar.
tabBarController.viewControllers = [NSArray arrayWithObjects:quoteController, bookmarkNavController,nil];
[bookmarkController release];
[quoteController release];
[window addSubview:tabBarController.view];

The first tab will be a custom tab set up via Interface Builder. The second tab will be a navigation controller. Mix, match and add to as necessary.

Once everything is loaded, in the initWithNib and the initWithTab you are able to set the properties such as the tab name or the navigation items with self as expected.

Jan 9, 2011, 10:16 PM
Thanks ulbador, but in the end, I left the Navigation Controller in the second tab's View Controller, and then in the view root controller, I did something like:

AddressViewController *addressViewController = [[AddressViewController alloc] initWithNibName:@"AddressView" bundle:nil];
ClientAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
WizardViewController *wizController = [delegate.rootController.viewControllers objectAtIndex:1];
[wizController.navController pushViewController:addressViewController animated:YES];

I don't know if the iPhone way is to do it the way I did it, or the way you did it, but if it works for now then it's good enough for me.

Jan 10, 2011, 08:12 AM
ViewControllers managed by the navigation controller have a property 'navigationController' that is already set up for you so you don't need to access it via app delegate. This should just work:

[self.navigationController pushViewController:someOtherVC animated:YES];