0

I need to detect when a tableview has finished reloading data. There was an older solution where you could subclass the tableview then overload the reloadData method, however apparently that no longer works because tables are handled on multiple threads now and reloadData is called before cellForRowAtIndexPath.

My question is, has there been any solution to this problem since the change?

My problem is I am losing the pointer to a textField when the table reloads its data, so the first responder I am trying to set to the next text field (to auto focus on the next data input field), is lost.

Monolo
  • 18,205
  • 17
  • 69
  • 103
JMD
  • 1,540
  • 2
  • 24
  • 56
  • 1
    Will this [answer](http://stackoverflow.com/questions/15218861/call-function-only-after-reloaddata-has-finished/15218941#15218941) serve you? – Anoop Vaidya Apr 26 '13 at 16:59
  • 1
    How are you creating this pointer? You should post some code for how you create and use this. The solution to your problem may not involve detecting the completion of viewDidLoad. – rdelmar Apr 26 '13 at 17:03
  • i dont really create it, it set the first responder using the pointer given to me in the `TextFieldShouldReturn` delegate method. But the table refreshes after this delegate is called, and I lose the pointer. Or, I suspect that is what is happening, because I set the first responder to the correct text field (ive checked the pointer I am setting it to) but focus is lost after the user hits return. – JMD Apr 26 '13 at 17:08
  • If you're reloading the table then the pointer is invalid even if you still have it as the table cell the text field is on has probably moved (been recycled). – Wain Apr 26 '13 at 17:17
  • @Wain so what is the solution to setting the first responder, then refreshing the table, and maintaining that textfield as first responder? – JMD Apr 26 '13 at 17:19
  • Is each text field on it's own table cell and the next responder is always the text field below the current one ? – Wain Apr 26 '13 at 17:24
  • yes, with the exception that this is a grouped table and once you reach the end of a group the keyboard goes away instead of moving to the next textfield. (code to handle that already exists though) – JMD Apr 26 '13 at 17:26
  • if you provide some code, someone will definitely help you with this – Jessica Apr 26 '13 at 17:44
  • @JMD, also wanted to mention (possibly not relevant). I had a case where I just needed to animate resizing of table cells for text entry. I found that calling beginUpdates/endUpdates instead of reloadData (or in my case reloadRowsAtIndexPaths:withRowAnimation:) performed the animations I needed without reloading the cells. Thus, subviews remain in their superviews, firstResponder remains firstResponder, no need to hassle with when to call becomeFirstResponder. – geraldWilliam Apr 30 '13 at 17:21

3 Answers3

1

This is essentially a repeat of @wain 's answer, but I thought I would add a little code.

You can keep a reference to the index path of the cell that owns the active text field (as a property).

Then, in cellForRowAtIndexPath: something like this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    //I would hold a reference to the text field as a property on a subclass of UITableViewCell so that you can check for whether it exists.

    if (!cell.textField) {

            cell.textField = [[UITextField alloc] initWithFrame:cell.contentView.frame];

            [cell.contentView addSubview:cell.textField];
        }

    return cell;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    UITableViewCell *cell = (UITableViewCell *)textField.superview.superview;

    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

    self.indexPathForActiveTextField = indexPath;
 }

- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
    MyTableViewCell *cell = (MyTableViewCell *)textField.superview.superview;

    NSIndexPath *ip = [self.tableView indexPathForCell:cell];

    [self.tableView reloadData];

    NSIndexPath *nextIndexPath = [NSIndexPath indexPathForRow:ip.row+1 inSection:ip.section];

    MyTableViewCell *theNewCell = (MyTableViewCell *)[self.tableView cellForRowAtIndexPath:nextIndexPath];

    if (theNewCell) {

        [theNewCell.textField becomeFirstResponder];
    }

    return YES;
}
geraldWilliam
  • 4,123
  • 1
  • 23
  • 35
  • this solution is not working for me, the way i guess these subclassed cells and textFields are set up. I am setting the first responder to the correct textfield, but focus is never shifted. Focus in any text field just goes away entirely. – JMD Apr 26 '13 at 18:42
  • @JMD, edited with a tested and working solution. looks like cellForRowAtIndexPath is not the place to call becomeFirstResponder. But you can just get the textField property of the reloaded custom UITableViewCell in textFieldShouldReturn (or whatever method is supposed to advance thru your cells), and call becomeFirstResponder there. – geraldWilliam Apr 26 '13 at 20:26
0

Store the NSIndexPath of the table cell that holds the text field that should be the first responder. When you want to change the first responder you can ask the table view for the cell at that index path, then find the text field and make it first responder.

If the table view gets reloaded, in cellForRowAtIndexPath: check the index path and make the 'new' text field the first responder.

In this way you can set the first responder at any time and you can't loose the reference to it as the reference is to a location, not an object (which will be reused or removed).

Wain
  • 118,658
  • 15
  • 128
  • 151
0

UITableView uses a pool to reuse displayed cell. The target cell is possibly reused in other row. Storing the NSIndexPath like Wain suggested is good untill you not reorder the cells or delete some entry from the datasource. Define a key in the model, that you set the firstResponder according to that. Hope i did not misunderstood the problem.

Peteee24
  • 510
  • 4
  • 8