4
votes

Sorry for the long story -

I have some issues about the proper usage of a navigation controller hierarchy.

Every UIViewController has a property self.navigationController

But not every view controller is presented from a navigation controller - therefor that property could be nil.

more so -

Some view controllers expect to be able to do:

[self.navigationController presentViewController:nextViewController];

but if it itself isn't contained in a navigation controller hierarchy, that expression would do nothing.

So intern the view controller could test if it was embedded in a navigation controller:

if (self.navigationController == nil)
{
  // create a UINavigationController with a root view controller - the next view controller
  UINavigationController *nav = [UINavigationController alloc] initWithRootViewController:nextViewController];
  [self presentViewController:nav];
}

but that might defeat the purpose - because if the presenting view controller isn't in a navigation controller - why would the next view controller necessarily need to be in a navigation controller. Why wouldnt't the current view controller just do:

[self presentViewController:nextViewController];

and skip the navigation controller creation?

On those exact lines - another issue that I am facing -

Some view controllers expect to be presented from a UINavigationController -

Because they set navigation items - toolbar items, titles etc. in the supplied navigation controller bars.

If for some reason their self.navigationController == nil - how can they "put themselves" inside a navigation controller in order to assure that they can access those expected elements???

About the container view controller inside a navigation controller issue:

If you look at the stock iOS music app - you can see what appears to be a UITabBarController embedded inside a UIViewNavigationController - each tab is a separate view controller - while each can "push" and "pop" view controllers themselves.

I need to achieve a similar effect (but with a different layout) so I created a container view controller with UITabBar view inside.

I then created a presentation container view inside that container view controller

This container was where each child view-controller's view was presented in. (those are the 'child view controllers' of the 'parent view controller') - this is a bit of tongue twister and I apologize for that.

Tab bar toggles - the parent view controller swaps the visible view controller in that container.

Now each view controller is very generic - they have no idea of their containment but expect to have a UINavigationController variable that is set (non-nil) in order to set titles - buttons - navigation items etc.

How can a generic black box view controller "present" itself (embed itself) in a navigation controller-

How can a container view controller set the navigationController property of a child view controller?

1

1 Answers

0
votes

I have an app that has a place-holder (self.mainView) for viewControllers to be placed based on a tab selection. Some of them need a NavigationController, and others don't. You can always do a test if self.navigationController == nil and work accordingly.

Here is some sample code I use to show a viewController into that place holder that may help you.

if (self.currentController) {
    [self.currentController willMoveToParentViewController:nil];
    [[self.currentController view] removeFromSuperview];
    [self.currentController removeFromParentViewController];
    self.currentController = nil;
}


switch (tag) {
    case 0:
        self.currentController = [self.storyboard instantiateViewControllerWithIdentifier:@"AboutViewController"];
        break;

    case 1: {
        UINavigationController *controller = [[UINavigationController alloc] initWithRootViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"EventsViewController"]];
        self.currentController = controller;
    }
        break;
}


if (self.currentController) {
    [self addChildViewController:self.currentController];
    [self.mainView addSubview:self.currentController.view];
    [self.currentController didMoveToParentViewController:self];
    [self adjustMainView];
    [self.view layoutIfNeeded];
}