UITableView reloadData automatically calls resignFirstResponder

Viewed 32727

I have this UITableView with custom cells that can get only predefined values, therefore I use a UIPickerView as their inputView. All is jolly good until I edit a field and need to show its updated value.

In order to make things clearer and easier to maintain, I made delegates and data sources as separate classes, and use notifications to make them interact with the tableView. So, after a value has been chosen from the UIPickerView, the tableView's data source gets notified, and in turn notifies the main ViewController that holds a reference to the tableView. From there I call

[_tableView reloadData];

and everything seems to work, except that the UIPickerView disappears, I think because the cells are regenerated and somewhere some resignFirstResponder is called, or something like that. Is there any other way to make the tableView updating its values without having to implement a custom method somewhere that does it, which would be quite ugly?

14 Answers

Here my solution. Think that search textfield is in index 0.. You need to update or add or remove next rows..

let beforeCount = self.filteredItems.count
self.filteredItem = ... next filtered items

var removalIndexPaths = [IndexPath]()
var appendalIndexPaths = [IndexPath](
var modifyIndexPaths = [IndexPath]()
self.tableView.beginUpdates()
let deleteAvailable = beforeCount != 0
if deleteAvailable {
    for i in stride(from: beforeCount - 1, to: 0, by: -1) {
        removalIndexPaths.append(IndexPath(row: i, section: 0))
     }
}
        
let appendAvailable = self.filteredShots.count != 0
if appendAvailable {
     for i in stride(from: 1, to: self.filteredShots.count, by: 1) {
         appendalIndexPaths.append(IndexPath(row: i, section: 0))
      }
 }
        
 modifyIndexPaths = appendalIndexPaths.filter { appendPath in
      if appendPath == removalIndexPaths.filter({ $0 == appendPath }).first {
         return true
     } else {
         return false
     }
 }
        
for item in modifyIndexPaths {
     if let rai = appendalIndexPaths.firstIndex(where: { $0 == item}) {
          appendalIndexPaths.remove(at: rai)
     }
     if let rri = removalIndexPaths.firstIndex(where: { $0 == item}) {
           removalIndexPaths.remove(at: rri)
      }
}
        
if modifyIndexPaths.count > 0 {
      self.tableView.reloadRows(at: modifyIndexPaths, with: .none)
}
        
if removalIndexPaths.count > 0 {
      self.tableView.deleteRows(at: removalIndexPaths, with: .none)
}
        
if appendalIndexPaths.count > 0 {
       self.tableView.insertRows(at: appendalIndexPaths, with: .none)
}
               
self.tableView.endUpdates()

Track which cell's keyboard is active and then get that particular cell by cellForRowAtIndexPath and make textView firstResponder

self.tableView.reloadData()
if let indexPath = self.activeIndexPath{
   if let cell = createFormTableView.cellForRow(at: indexPath) as? TextViewTableViewCell {
        cell.txtViewInput.becomeFirstResponder()
   }
}

I use beginUpdate and endUpdate After end update, get the cell contains the textfield already has focus then make it first responder

    self.tableView.beginUpdates()
    self.tableView.reloadRows(at: [indexPath], with: .automatic)
    self.tableView.endUpdates()
    let newCell = self.tableView.cellForRow(at: indexPath)
    newCell.textField.becomeFirstResponder()
Related