textFieldShouldEndEditing called multiple times

旧城冷巷雨未停 提交于 2019-12-10 13:17:15

问题


I am working on a view that has multiple UITextField objects. My view controller serves as the UITextFieldDelegate, and I've implemented the (BOOL)textFieldShouldEndEditing:(UITextField *)textField method to save and validate the record being displayed.

If the user clicks on the "Done" button after editing an item and the save/validate fails, then a UIAlertView is displayed and the user is kept on the UITextField that fails validation.

My problem is this -- when a user clicks from the UITextField that will fail save/validation onto another of the UITextFields, then the (BOOL)textFieldShouldEndEditing:(UITextField *)textField method is called multiple times, and the UIAlertView pops up multiple times.

Why is (BOOL)textFieldShouldEndEditing:(UITextField *)textField called once when the user clicks "Done" on the keyboard, but called multiple times when the user clicks onto another UITextField?

Here is my code:

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    NSLog(@"textFieldShouldEndEditing called by textField with text=%@", textField.text);

    currentItem.nameOrNumber = nameOrNumber.text;

    // Try to save the managed object.
    NSError *error = nil;
    if (![[currentItem managedObjectContext] save:&error]) {        
        UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Uh Oh!",@"")
                                                             message:[error localizedDescription]
                                                            delegate:self
                                                   cancelButtonTitle:NSLocalizedString(@"OK",@"")
                                                   otherButtonTitles:nil];
        [errorAlert show];
        [errorAlert release];
        shouldEnd = NO;
    }

    return shouldEnd;
}

回答1:


I think your problem comes from the order in which textField methods are called when you are editing a textField and directly tap onto another.

If I am not mistaken, it should be something like this (you are editing on A and tap on B)

  • textFieldShouldBeginEditing for field B
  • textFieldShouldEndEditing for field A
  • textFieldDidEndEditing for field A
  • textFieldDidBeginEditing for field B

So when you are in textFieldShouldEndEditing method, textfield B already has become the first responder. So when you make the UIAlertView appear, B loses focus and thus calls textFieldShouldEndEditing too!

This also has been a problem for me when I wanted to raise a view when a textField started editing. The solution I found was to create a boolean class variable indicating whether or not I am currently switching from one textField to another. I set it to TRUE in textFieldShouldBeginEditing and to FALSE in textFieldDidBeginEditing. When you're in textFieldShouldEndEditing, if it is set to TRUE it means the user directly tapped on another textField. Then you just have to find the right way to make your tests only once (maybe shouldEndEditing should return false or something).




回答2:


Another option is to let the UIAlertView fake a correct validation and defer the correcting part to a latter time. Something like this :

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    double delayInSeconds = 0.;
    self.currentTextField.text = @"Something that won't trigger validation error";
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        // do what you need here
    });
}



回答3:


Looks right for me to be called 2 times for each test field. Why? just think about... had passed to me also and get me headache

You can NOT do some like this

- (BOOL)textFieldShouldEndEditing:(UITextField *)txtField{

if(i_dont_know){
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" 
                                                    message:@"Message"
                                                   delegate:self 
                                          cancelButtonTitle:@"Ok" otherButtonTitles: nil];
    [alert show];
    [alert release];
    return false;
}

return true;}

Is that the UIAlertView show is also trying to resign the editing of text field and calling this funcion "textFieldShouldEndEditing:"...

So my way to solve this was to add a member variable called "shouldEndEditing" in the interface delaration, who is true por default. And after the "textFieldShouldEndEditing:" can be some like this.

- (BOOL)textFieldShouldEndEditing:(UITextField *)txtField{

if(shouldEndEditing == false)
{
    shouldEndEditing = true;
    return false;
}

if(i_dont_know){
    shouldEndEditing = false;
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" 
                                                    message:@"Message"
                                                   delegate:self 
                                          cancelButtonTitle:@"Ok" otherButtonTitles: nil];
    [alert show];
    [alert release];
    return false;
}

return true;}

Good luck...




回答4:


Couldn't you add different tags in each textview and check the tag in the textFieldShouldEndEditing? Or have I missed the point?



来源:https://stackoverflow.com/questions/3121440/textfieldshouldendediting-called-multiple-times

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!