71

In my MainStoryBoard I want to push a viewController to the detailView but I get this error:

NSInvalidArgumentException', reason: 'Pushing a navigation controller is not supported'

I set the identifier 'JSA' ID for the viewController on the storyboard.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
        SWSJSAViewController *viewController = [[UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:@"JSA"];
        [self.navigationController pushViewController:viewController animated:YES];
    }
}
Hexfire
  • 5,945
  • 8
  • 32
  • 42
Jose
  • 1,027
  • 1
  • 14
  • 23
  • 63
    You have to push a view controller, not another navigation controller. If you really want to display another navigation controller, you need to present it, not push it. – rmaddy Jul 19 '13 at 23:45
  • Thanks a lot ready, the error is gone, but it goes to the tableViewController, I want it on the detail, Thanks – Jose Jul 20 '13 at 01:02
  • Take a look at this thread http://stackoverflow.com/questions/10817305/pushing-a-navigation-controller-is-not-supported-performing-segues/23102975#23102975 (I've got an answer that worked for me, but maybe one of the others will do the trick for you.) – LordParsley Apr 16 '14 at 07:42
  • 1
    Like maddy said, this raises an exception with "Pushing a navigation controller is not supported". You have to [self presentViewController: viewController animated:YES completion:nil]; – jos May 27 '16 at 08:15
  • also make sure you hv entered storyboard identifier in viewcontroller, not in navigationcontroller – Gajendra K Chauhan Feb 06 '17 at 04:14
  • Navigation Controller can't contain Navigation Controller again. It should be only one. – Farras Doko Apr 23 '21 at 07:42

2 Answers2

51

Like rmaddy said in the comments you are trying to push a navigation controller.

Navigation controllers should be presented (via presentViewController or they can be added as a childViewController) and ViewControllers should be pushed.

Community
  • 1
  • 1
Tiago Almeida
  • 14,081
  • 3
  • 67
  • 82
38

When you talk about pushing Navigation Controller, it is most likely that you want to present it.

  1. Presenting UINavigationController

This is the most common way and this is what you want to do in most cases. UINavigationController cannot be pushed, it can only be presented with a new root View Controller.

MyViewController* vc = [[MyViewController alloc]
      initWithNibName:@"MyController" bundle:nil];

UINavigationController *myNav = [[UINavigationController alloc] initWithRootViewController: vc];

[self presentViewController:myNav animated:YES completion:nil];

What you do here, is firstly create a UINavigationController and then set necessary UIViewController as its root controller.


  1. Pushing UINavigationController

If you have a hierarchy of ViewControllers and you need to push view controller that contains navigation controller within, steps are:

1) Push ViewController, containing UINavigationController.

To push UINavigationController, first create a subclass of UIViewController, which will be a wrapper-/container- class for your UINavigationController and its content.

ContainerViewController* vc = [[ContainerViewController alloc] init];

2) Adding UINavigationController as a child view controller

In viewDidLoad of your container (that you have just instantiated) simply add something like this:

Objective-C

UINavigationController* myNav = [[UINavigationController alloc] initWithRootViewController: rootViewController];
[myNav willMoveToParentViewController:self];

myNav.view.frame = self.view.frame;  //Set a frame or constraints
[self.view addSubview:myNav.view];
[self addChildViewController: myNav];
[myNav didMoveToParentViewController:self];

Swift 4.2+

let childNavigation = UINavigationController(rootViewController: viewController)
childNavigation.willMove(toParent: self)
addChild(childNavigation)
childNavigation.view.frame = view.frame
view.addSubview(childNavigation.view)
childNavigation.didMove(toParent: self)

What you do here is basically instantiate your navigation controller and add it as a child controller to your wrapper. That's it. You have successfully pushed your UINavigationController.

Hexfire
  • 5,945
  • 8
  • 32
  • 42
  • This is a much more comprehensive answer which addresses the need to support hierarchical navigation controllers without modal presentation. Should be the top answer. – ricosrealm Apr 11 '18 at 21:42
  • There is a problem with UINavigationItem in embedded navigation controller. You can't add bar buttons easily. Problem is that the original navigation item from parent is used so you have to access it like `parent.navigationItem...`. And that's very bad from the point of reusability of view controllers. – Deny Feb 04 '19 at 17:26
  • @Deny Yes, there's an issue. But you can handle it by hiding parent navbar and managing inherent navigationItem. From UI perspective, it would look equal. – Hexfire Feb 06 '19 at 10:58
  • @Hexfire It's not so easy. If you hide the parent navbar you can't use the system back button. Therefore you have to add the custom back button in child navbar and that's ugly as calling the navigation item through its parent. – Deny Feb 06 '19 at 13:07