Get indexPath of UITextField in UITableViewCell with Swift

Using superview and typecasting isn't a preferred aaproach. The best practice is to use delegate pattern. If you have a textField in DemoTableViewCell which you are using in DemoTableViewController make a protocol DemoTableViewCellDelegate and assign delegate of DemoTableViewCell to DemoTableViewController so that viewcontroller is notified when eiditing ends in textfield.

protocol DemoTableViewCellDelegate: class {
  func didEndEditing(onCell cell: DemoTableViewCell)
}

class DemoTableViewCell: UITableViewCell {
  @IBOutlet var textField: UITextField!

  weak var delegate: DemoTableViewCellDelegate?

  override func awakeFromNib() {
    super.awakeFromNib()
    textField.delegate = self
  }
}

extension DemoTableViewCell: UITextFieldDelegate {
  func textFieldDidEndEditing(_ textField: UITextField) {
    delegate.didEndEditing(onCell: self)
  }
}

class DemoTableViewController: UITableViewController {

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: DemoTableViewCell.self, for: indexPath)
    cell.delegate = self
    return cell
  }

}

extension DemoTableViewController: DemoTableViewCellDelegate {
  func didEndEditing(onCell cell: DemoTableViewCell) {
    //Indexpath for the cell in which editing have ended.
    //Now do whatever you want to do with the text and indexpath.
    let indexPath = tableView.indexPath(for: cell)
    let text = cell.textField.text
  }
}

You'll want to cast the first and second lines in your function, like this:

func textFieldDidEndEditing(textField: UITextField!){
    var cell: UITableViewCell = textField.superview.superview as UITableViewCell
    var table: UITableView = cell.superview as UITableView
    let textFieldIndexPath = table.indexPathForCell(cell)
}

superview returns a UIView, so you need to cast it to the type of view you expect.


While the currently accepted answer might work, it assumes a specific view hierarchy, which is not a reliable approach since it is prone to change.

To get the indexPath from a UITextField that is inside a cell, it's much better to go with the following:

func textFieldDidEndEditing(textField: UITextField!){
    let pointInTable = textField.convert(textField.bounds.origin, to: self.tableView)
    let textFieldIndexPath = self.tableView.indexPathForRow(at: pointInTable)
    ...
}

This will continue to work independent of eventual changes to the view hierarchy.