views:

506

answers:

6

In my iPhone application I have navigation controller, main screen and some edit screens. On edit screen user does some input that has to be validated before I can save it. Ideally I would like to update data automatically on back navigation without additional "Done" button. Can I do some validation and save on back navigation (i.e. when user taps on standard back button) in a way that allows my to stop navigation and show some error message if something is wrong?

I see several other possibilities:

  • Create my custom left button and make it looks like standard back. (Why Apple didn't put this button style into public API?)
  • Add "Done" button and save data only if user taps it

but both these choices I like much less. So if there is a way to achieve what I want, I'd like to use it.

+2  A: 

Basically you want to override the action from the backBarButton of your root view controller and do your validation there. If validation passes call the UINavigationController popViewControllerAnimated:, otherwise show an error alert or whatever.

However, if you try to set the target and action properties for the root view controllers navigationItem.backBarButton it won't work. Apparently these have to be nil.

A way round this maybe to replace the standard back bar button with a custom button. You could do that with a standard UIBarButtonItem, but you would lose the 'arrow' shape since this is not available as one of the styles. A workaround for that maybe to use a custom view for the button. Check out this thread for an example of doing that.

cidered
iPhone beginner
A: 

Just override [popViewControllerAnimated:] in your UIViewController subclass. That way you cover the more general scenario of the view controller leaving the screen.

refulgentis
Can't do that: popViewControllerAnimated comes from UINavigationController, not UIViewController... he would have to make a specific (and separate) descendant of UINavigationController just for this - not recommended at all.
Zoran Simic
A: 

The best way I found to "detect when the Back button is pressed" is to redefine viewWillDisappear like so:

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    if (!isPushing) {
        // Apply your changes here
    }
}

The boolean isPushing would be one that you define yourself, and you set it to True only in places where you push another another controller yourself (if you do...), that allows you to distinguish between viewWillDisappear being called because you're pushing a new controller yourself vs because the Back button was pressed.

You usually push another controller yourself in a table controller like so:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Example of pushing a new controller onto the navigation stack yourself...
    isPushing = YES;    // You have to set that boolean here...
    [self.navigationController pushViewController:myNewController animated:YES];
}
Zoran Simic
I know that I can intercept the event, the thing is that I don't see a way to stop navigation at this moment. And if I can't stop navigation I can't do anything reasonable if input validation fails
iPhone beginner
A: 

Another approach, if, say, the user is tapping one row in a UITableView would be to have the tap initiate the view controller pop.

Frank Schmitt
A: 

An alternative way is to have your parent view do the work.

Say you navigate from a data view (e.g., Contact Information) to a field-edit view (e.g., Name Edit). Before going the edit view, the data view store some information about this fact, e.g.:

self.navigatingTo = NavigatingToNameEdit;

Then in your data view's viewWillAppear, check for that and extract the relevant information from the edit view:

if (self.navigatingTo == NavigatingToNameEdit) {
    self.name = self.nameEditView.name;
    // Don't forget to reset navigatingTo:
    self.navigatingTo = NavigatingToNone;
}
squelart
A: 

While you've probably moved on from this a while ago, I just ran into this issue today. My guess is that Apple doesn't want you overriding the action of those back buttons. My solution was to display and alert view (which displays on the view controller that you've just moved to) and use AlertViews delegate method "clickedButtonAtIndex" to move the user back to the screen with the errors. Overall I think it actually comes across pretty clean. My 2 cents...

Staros