views:

33

answers:

3

I am sure this is in the Apple documentation or must have been answered somewhere on this forum, since it seems so basic, but I could not find it nor a particularly elegant solution myself.

What I have is a UIViewController that pushes an editing view on its navigation stack. The editing view has a bunch of UITextFields in it. If one of them is being editing when the back button is touched, the original view's ViewWillAppear method is called before either the UITextField delegate methods of textFieldShouldEndEditing or textFieldDidEndEditing, or the IB linked action textFieldEditingEnded method are called.

Here is some code that I hope will make it clearer:

In the UIViewController:

- (void) viewWillAppear: (BOOL) animated {
    [super viewWillAppear: animated];
    NSLog( @"Entering view will appear for master view" );
    nameLabelField.text = objectToEdit.name;
}
- (IBAction) editMyObject: (id) sender {
    NSLog( @"Editing the object" );
    EditViewController *evc = [[EditViewController alloc] initWithNibName: @"EditTableView" bundle: nil];
    evc.editedObject = objectToEdit;
    [self.navigationController pushViewController: evc animated: YES];
    [evc release];
}

In the EditViewController <UITextFieldDelegate>:

- (void) viewWillAppear: (BOOL) animated {
    [super viewWillAppear: animated];
    nameField.text = editedObject.name;
}
- (void) viewWillDisappear: (BOOL) animated {
    [super viewWillDisappear: animated];
    NSLog( @"In viewWillDisappear" );
    if( [self.navigationController.viewControllers indexOfObject: self] == NSNotFound ) {
        NSLog( @"-- We are not in controller stack... the back button has been pushed" );
    }
}
- (BOOL) textFieldShouldEndEditing: (UITextField *) textField {
    NSLog( @"In textFieldShouldEndEditing" );
    // Store text field value here???
    // editedObject.name = nameField.text;
    return YES;
}
- (void) textFieldDidEndEditing: (UITextField *) textField {
    NSLog( @"In textFieldDidEndEditing" );
    // Store text field value here???
    // editedObject.name = nameField.text;
}
- (IBAction) textFieldEditingEnded: (id) sender {
    NSLog( @"In textFieldEditingEnded" );
    // Store text field value here???
    // editedObject.name = nameField.text;
}

The log ends up with:

[...] Entering view will appear for master view
[...] Editing the object
[...] In viewWillDisappear
[...] -- We are not in controller stack... the back button has been pushed
[...] Entering view will appear for master view
[...] In textFieldShouldEndEditing
[...] In textFieldEditingEnded
[...] In textFieldDidEndEditing

I want to set self.editedObject.name = nameField.text before the label gets set in viewWillAppear for the UIViewController.

I thought about in the viewWillDisappear method for the EditViewController checking to see if any of my text fields are currently the first responder and if so getting their text and storing it, but this seems like such a kludge that will be a pain to maintain if I add or change text fields.

I can also implement the textFieldEditingChanged IB linked action to set the text in the edited object after every keystroke but this is also quite a bit of overhead since I have to figure out which text field I am in every keystroke (remember I only showed name but there are a whole bunch of them).

All I need is for the editing to be ended or to know the editing will be ended before viewWillAppear is called in the UIViewController so the nameFieldLabel is properly set.

A: 

Why not just create your own Back button with that logic in its action method?

Jeff Kelley
Thanks for the suggestion Jeff. This may be what I need to do but I loose the native-appearing UI of the button with the pointy end, unless I do a lot of work crafting a custom button by making a PNG file for it, etc., etc., I am willing to do that if I have to, in order to get the functionality, but I'm hoping for something I am missing to just add to my code.
LavaSlider
A: 

I would think that from a UX perspective, you should display an alert to determine if the user wants to cancel the edit action they were in the middle of before exiting the current view.

By alerting the user, you can see if they hit the button by accident or if they did decide to leave the view, take the appropriate action.

// add this to the field(s) to be edited, selector will be called as the changes
// are being made... still difficult to handle a cancel, but should work
[objectToEdit addTarget:self action:@selector(updateNameField:) 
                         forControlEvents:UIControlEventEditingChanged];

additional code here...

// the method called to update object from parent view
- (void)updateNameField:(id)sender {
    <OBJECT TO UPDATE>.text = ((UITextField *)sender).text;
}
Aaron Saunders
I would be OK with that. I was really thinking that it would be an intentional back button... why have to hit Done then Back? I suppose requiring that precludes accidental "Back"s. But this does not provide any help since I don't have a way of knowing whether to present the alert since I don't know what or if a text field is in the process of being edited.
LavaSlider
@LavaSlider see edits, to do something like textFieldEditingChanged you were discussing
Aaron Saunders
@LavaSlider not too hard to implement something like textFieldEditingChanged. See edits above for solution
Aaron Saunders