0
votes

I am using view controller containment, and as part of my implementation a child view controller needs to disable a bar button item of the navigation controller of the parent view controller. The theory is that being a child view controller, I had access to the same navigation controller (in my context anyway) as the parent view controller's.

From debugging I can see that self.navigationController and self.parentViewController.navigationController were set to the same address.

For example:

NSLog(@"%@ - %@", self.navigationController, 
                  self.parentViewController.navigationController);

NSLog(@"%@ - %@", self.navigationItem, 
                  self.parentViewController.navigationItem);

NSLog(@"%@ - %@", self.navigationController.navigationItem, 
                  self.parentViewController.navigationController.navigationItem);

Resulted in the following console log:

<UINavigationController: 0xc482290> - <UINavigationController: 0xc482290>

<UINavigationItem: 0xa5f3620> - <UINavigationItem: 0xc482490>

<UINavigationItem: 0xa5f36e0> - <UINavigationItem: 0xa5f36e0>

Results

  • Navigation controllers are the same, as expected (self->navController == self->parent->navController).
  • Navigation item's are different, this is expected. Each view controller has it's own nav item (self->navItem != self->parent->navItem).
  • Accessing the navigation controllers nav item from the parent or the child view controller is identical, as expected (self->navController->navItem == self->parent->navController->navItem)

So I now ask: why didn't disabling a bar button item in the child view controller with the following code work:

self.navigationController.navigationItem.rightBarButtonItem.enabled = NO;

This should be synonym to the following (which does work as expected) given their shared address:

self.parentViewController.navigationController.navigationItem.rightBarButtonItem.enabled = NO;

Update

I was reading my logs too fast. Indeed the parentViewController and the navigation controller have 2 different navigation items. I missed this in my example here because the memory addresses were extremely close: 0xa5f3620 != 0xa5f36e0

2
Are you performing the comparisons and the assignments within the same method? - murat
Is navigationController.navigationItem supposed to return the navigationItem of the top most controller within its stack, or its own navigationItem? - Mike Pollard
@MikePollard navigation controller inherits this from the view controller class, since it's the same address I'm assuming it is using the topviewcontroller's navigation item. - Daniel

2 Answers

1
votes

A UINavigationController has it's very own navigationItem (like any other UIViewController) that will only come into play if you push it onto the stack of another UINavigationController.

Generally you aren't going to push one UINavigationController onto another so manipulating self.navigationController.navigationItem is pointless.

EDIT:

To check ... I've just aded:

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    UINavigationItem *myNavControllersItem = self.navigationController.navigationItem;
    UINavigationItem *myItem = self.navigationItem;
    NSLog(@"%@ - %@", myNavControllersItem, myItem);
}

to a VC that I'm pushing onto a NavController and get:

<UINavigationItem: 0x1ed0c170> - <UINavigationItem: 0x1ed46330>

Additionally, if I add:

self.navigationItem.rightBarButtonItem.enabled = NO; to viewDidAppear the right button gets disabled.

if I add:

self.navigationController.navigationItem.rightBarButtonItem.enabled = NO; it does not.

1
votes

Well basically the problem is the way the navigation controller updates the bar button items, basically the buttons are update whenever the top-level child is changed. For the right bar button item, if the new top-level child has it's own bar buttons items then the navigation controller will select the existing one, if not nothing will be displayed. So in your case the parrentViewController already has a navigationItem.rightBarButonItem which is not disabled, by calling self.navigationController.navigationItem.rightBarButtonItem.enabled = NO; you are disabling the child's nabigationItem.rightBarButtonItem and you can't see this because the updates are made only when the top-level child is changed which is not your case.

So in order to disable the parentViewController right button you should do: self.parentViewController.navigationItem.rightBarButtonItem.enabled = NO

For more details regarding the nav bar button updates please check apple docs regarding the Updating Navigation Bar Items