1

After any row is deleted by deleteRows(at:with:) from my Table View, I cannot get textfield in a reusable custom cell to get focus by becomeFirstResponder() (which is called after insertRows(at:with:) is called). becomeFirstResponder() is always called within cellForRow(at:).

This problem always starts occuring after a row is deleted from the table view by deleteRows(at:with:). Before any row is deleted there is no problem, becomeFirstResponder() can give focus to the textfield as intended.

I made some tests to understand why this problem occurs after a row is deleted... My tests showed an interesting difference:

Case 1: After any row is deleted (i.e. while becomeFirstResponder() returns false), textFieldShouldBeginEditing(_:) is called BEFORE cellForRow(at:) returns. textFieldDidBeginEditing(_:) is never called.

Case 2: On the other hand, before any row is deleted (i.e. while becomeFirstResponder() returns true), textFieldShouldBeginEditing(_:) is called AFTER cellForRow(at:) returns. textFieldDidBeginEditing(_:) is called immediately after textFieldShouldBeginEditing(_:), as expected.

The problem might be related to this difference, but I couldn't solve this mystery after trying & researching for many hours.

In a related Q&A, it is suggested not to reload tableView from within textFieldDidEndEditing(). In my case, deleteRows(at:with:) method are sometimes called from within textFieldDidEndEditing() and sometimes called from tableView(_:commit:forRowAt:) (i.e. by swiping to left). So this does not explain my problem. Another related Q&A might be this one.

getFocus() in CustomCell's class, called from cellForRow(at:) in TableViewController:

func getFocus() {
    if let itemTextField = itemTextField {
        itemTextField.delegate = self
        itemTextField.isUserInteractionEnabled = true
        itemTextField.becomeFirstResponder()
    }
}

cellForRow(at:):

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let item = items[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
    cell.setCell(item: item)
    cell.delegate = self

    if insertingRow == true {
        if isTempItem(item: item, indexPath: indexPath) {
                cell.getFocus()
        } else {
            print("isTempItem returned false, no need to give focus.")
        }
    }

    return cell     
}
Luke
  • 965
  • 8
  • 21
  • Don't call `getFocus` in `cellForRowAt`. The cell may not even be added to the table view yet. – rmaddy Jul 02 '19 at 00:12
  • It seemed to me that is the only place where I can get access to the cell. Where else can I call it? Any suggestions please? – Luke Jul 02 '19 at 00:15

1 Answers1

0

Don't call getFocus in cellForRowAt, Insteed of when you insert new row, You can scroll to new row and call getFocus in willDisplayCell.

Hope to help you.

Thanh Vu
  • 1,599
  • 10
  • 14
  • This solved my problem. In fact I tried to use willDisplayCell but couldn't figure out how to use a custom cell with that method. With a little research I figured that out too. Thank you! – Luke Jul 02 '19 at 01:35