iPhone: Save with validation on back navigation
In my iPhone a开发者_开发技巧pplication 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.
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.
Just override [popViewControllerAnimated:] in your UIViewController subclass. That way you cover the more general scenario of the view controller leaving the screen.
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];
}
Another approach, if, say, the user is tapping one row in a UITableView would be to have the tap initiate the view controller pop.
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;
}
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...
精彩评论