0

I have a grouped table view and trying to set a new first responder to a text field when the user hits enter.

This is nothing new to me, and my code worked before I made some unrelated changes and now it doesn't. I have a pointer to the correct text field when I set its first responder, nothing happens.

Focus goes away entirely from any text field and the keyboard stays on screen. Then both the enter and 'hide keyboard' keys stop functioning until the user re-initiates focus on a text field again.

Here is the code:

- (void)uiTextFieldShouldReturn:(ObjectEditTextField *)uiTextField
 {
        if ((group.fields.count - 1) > uiTextField.fieldTag) 
        {

       //loop through every table group
        for (int i = uiTextField.fieldTag + 1; i < group.fields.count; i++) {

            //get whatever field is in the row (not necessarily a text field)

            ObjectEditField *field = [group.fields objectAtIndex:i];

            // a check if the field is of type UITextField
            if (field.propName && field.updateObjectOnEdit == YES && [field isKindOfClass:[UITextField class]]) {
                // set the active field
                activeField = field;

                // adjust the table view offset to make sure the text field is visble
                [self setTableViewOffsetForTextField:field];

                // obtain a pointer to the textfield object and set it to be the first responder
                UITextField *textField = (UITextField *)field;
                NSLog(@"field %@", textField.fieldLabel);
                if (![textField.field isFirstResponder]) {

                    [textField.field becomeFirstResponder];
                    return; 
                }
                break;
            }
        }
    }
Jim Puls
  • 79,175
  • 10
  • 73
  • 78
JMD
  • 1,540
  • 2
  • 24
  • 56
  • 1
    What is focus ? How are you able to get rid of "focus" if "nothing happens" ? Do you have previous version without "unrelated changes" to check against the same device/simulator ? – A-Live Apr 16 '13 at 16:09
  • My guess is that the problem is not related to this code at all. Check what happens inside your textfield (`ObjectEditField`) code. Maybe it is doing something when `becomeFirstResponder` is called? Maybe it is blocking the main thread? Maybe something else happen in between and some other field becomes the first responder? – Sulthan Apr 16 '13 at 16:12
  • Is it inside a modal view controller? – Sulthan Apr 16 '13 at 16:13
  • @Sulthan yes this is inside a modal view controller – JMD Apr 16 '13 at 16:46
  • @A-Live by focus I mean when you have a text field in focus, you get that flashing line inside the field to show if you type, characters will appear there. That shows 'focus.' When I assignFirstResponder, that goes away from the current text field(as it should) but focus is never set in the new text field – JMD Apr 16 '13 at 16:47
  • Was it presented as modal before or that is one of "unrelated changes" ? – A-Live Apr 16 '13 at 16:52
  • The unrelated change is that the data a user inputs is stored into a dictionary now rather than an object. and if this data is viewed again, its populated with the dictionary rather than an object. To answer your question though, yes, this view was presented in a modal both before and after it stopped working. – JMD Apr 16 '13 at 16:55
  • Thanks, it makes me think about some strange (still may be [as-intended](http://stackoverflow.com/a/3386768/792677) though) race conditions, if you are able to test the version w/o this changes that might be actually helpful. – A-Live Apr 16 '13 at 17:05

2 Answers2

0

First off, I would absolutely verify that your description above that your code "worked before" and the changes are "unrelated". Any changes you made to working code, by definition, in some way contributed to it not working any longer. If not directly, then indirectly due to a side effect.

All that jumps out at me from your posted code sample is the line:

// adjust the table view offset to make sure the text field is visble
[self setTableViewOffsetForTextField:field];

You are doing the right thing ensuring that that the cell containing the textField is scrolled into view. One possibility is that the cell is created when you scroll it into view which, depending on the rest of your code, may cause issues such as:

  1. the textField you are sending becomeFirstResponder to is a different instance than the textField actually in the cell.

  2. the cell hasn't been created yet when you call becomeFirstResponder due to animating scrolling the cell with the textField into view.

I would back out any changes you made to go back to a working version and really ensure the correct textField is being sent becomeFirstResponder at an expected time.

XJones
  • 21,959
  • 10
  • 67
  • 82
  • The only thing that changed was this file saves data to a dictionary rather than an object. Nothing else was altered. In this current case I am testing, the cells I am trying to set the first responder to are actually still visible and no scrolling is occurring. (they are two adjacent rows) And I do agree that something had to of changed. I just have no idea what since the only thing really altered was where data is saved to. – JMD Apr 16 '13 at 16:54
0

By comments, the field is inside a modal (presented) controller.

First an explanation - by default, if a text field in a modal controller loses focus, the keyboard is not hidden. This is controlled by method -[UIViewController disablesAutomaticKeyboardDismissal]

The default implementation of this method returns YES when the modal presentation style of the view controller is set to UIModalPresentationFormSheet and returns NO for other presentation styles. Thus, the system normally does not allow the keyboard to be dismissed for modal forms.

This explains why the keyboard behaves the way it behaves. No text field is focused and the keyboard is not hidden only because we are inside a modal controller.

So, what happens? We know that the current text field resigns first responder and either no view becomes first responder or a non-editable view becomes first responder.

Well, you whole code looks very suspicious:

ObjectEditField *field = [group.fields objectAtIndex:i];

Here we have an object of type ObjectEditField

[field isKindOfClass:[UITextField class]]

Now, we are testing, if the field is a subclass of UITextField. That's very suspicious. If it's ObjectEditField, how it can be UITextField, too?

Let's continue

UITextField *textField = (UITextField *)field;

Okey, let's assume it's a UITextField

if (![textField.field isFirstResponder]) {

Again, something very suspicious. A UITextField has no field property.

So:

[textField.field becomeFirstResponder];

is called on an unknown object. We don't even know if it's a UITextField.

Note that most of the code should issue warnings in your IDE.

Solution:

  1. Clean up your code, check warnings.
  2. Put a NSLog(@"%@", textField.field) before the becomeFirstResponder call. Check the log.
Sulthan
  • 128,090
  • 22
  • 218
  • 270