I’ve brought an old project out of the moth balls recently, the Migraine Diary application I wrote as part of my master’s thesis. It was my first “real” iPhone app and I call tell I didn’t know what I was doing entirely looking through the code. What this has forced me to do, however, is re-learn some of the basics of iOS development and of Apple design patterns. I have been spending some time back in the Apple developer documentation and will probably be posting some of the gotchas that tripped me up two years ago and I’m solving now with the better, more elegant solution.
Navigation controllers are very useful things to have in your app, and are probably the easiest thing to implement WRONG. Two years ago, I assumed any time I needed a navigation bar up top that I needed to create a UINavigationController and make my view the root controller of it. Silly me.
One of the problems I was facing in the Migraine Diary app was changing the back button text when I was one or more levels deep into a navigation controller. My main view was titled “Journal Entries” and my child view “Journal Entry”. By default, the controller will title the back button as “Journal Entries” which you can see clutters up the screen.
I found a lot of ways of hacking the title online, but there is really only one “right way” according to Apple. The button titled “Journal Entries” is actually owned by the parent view. Before you push the child view onto the navigation controller, do something like this:
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@”Back” style:UIBarButtonItemStyleBordered target:nil action:nil];
[[self navigationItem] setBackBarButtonItem:backButton];
Take note that you’re referring to [self navigationItem] not [[self navigationController] navigationItem] since you are in the PARENT controller.
Thanks for the tutorial. But, if I want to add a target and action is that possible???
It is possible to add an action and target to the UIBarButtonItem. However, I don’t think it’s guaranteed that the API will fire off that action if you’re setting the “backBarButtonItem” on the navigation item. The documentation for the backBarButtomItem says you should not set an action and target; they should be nil. If you’re looking at having a button perform an action, just set the leftBarButtonItem with your custom UIBarButtonItem having the action, and let it perform the pop instead of the built in back item. A good example of when you’d do this is if you want “back” to be a cancel button.
Thanks for the simple but useful guide!
you are really good man! thanks
I want to disable the back button on the current view, like from your Journal Entry view above. Is this possible?
I think I get that the back button is owned by the parent so I have been trying like this:
UIViewController *parent = (UIViewController *)self.delegate; //the delegate happens to be the parent
parent.navigationItem.backBarButtonItem.title = @”blah”; //that’s the parent but it’s not changing the title
parent.navigationItem.backBarButtonItem.enabled = NO; //doesn’t work
self.navigationItem.hidesBackButton = YES; //works but I don’t want to hide it
I’ve never tried disabling a navigation item before that was a back button; usually only buttons that do something like “Done”. Asking the parent to disable the navigation item is probably improper design; the parent provides the navigation item but if the context of the child screen is what determines if that is enabled or not, then the child should disable it/own the state of it.
What you might be able to do is something like (in the child):
self.navigationController.navigationItem.backBarButtonItem.enabled = NO;
When you push a view controller onto a Nav controller it should automatically set that accessor to the nav controller. That’s probably the safest way to access it without having to know how the parent controller operates.
If that doesn’t work, then it may not be possible to disable a back button.
I hadn’t tried that one but it didn’t work either. So, for now at least, I’ve just hidden it. Thanks.
I’ve confirmed with some sources online that backBarButtonItem ignores the enabled flag. The HIG somewhat dictates that a disabled back item isn’t acceptable; use navigationItem.hidesBackButton if the back button isn’t appropriate.
You’re welcome for the help, I frequently refer back to my posts for a memory jogger 🙂
And I forgot to mention that I use the code you posted above all the time! Thank you.
thanks for guiding. Great tutorial.