1
votes

I'm making a UIView extension that returns a possible UITableViewCell if that particular instance of UIView is indeed a subview of a UITableViewCell.

The idea is later I can pass that UITableViewCell reference to UITableView's indexPath(for:) method to get the cell's index path.

So if my table view cells contain UITextField, I'm able to identify which cell that text field comes from when UITextFieldDelegate's textFieldDidEndEditing(_ textField: UITextField) method is called.

So far this is what I came up with:

extension UIView {
    var tableViewCell: UITableViewCell? {
        get {
            var view = self
            while let superview = view.superview {
                if let tableViewCell = superview as? UITableViewCell {
                    return tableViewCell
                }
                view = superview
            }
            return nil
        }
    }
}

I have 2 questions:

  1. Since I'm new to programming with Swift, may I know if there is a better (Swiftier?) way to write this?

  2. Is this a good way of identifying the index path of a UITableViewCell which contains a UITextField that is being edited? Is there a better way?

I'm actually new both to Swift and Stack Overflow, so sorry if I do something wrong (please be more forgiving) and I wish for your guidance. Thank you.

3

3 Answers

2
votes

The cleanest method to do this is simply tag your cell textField.

For example, you can also tag with indexPath.row.

Then in the UITextFieldDelegate method textFieldDidBeginEditing(_:) simply check the tag of the textField that begins editing and you can simply create an NSIndexPath from it.

However, if you have multiple sections and UITextFields in different secitons, you need both section and rowfor the NSIndexPath to be correct.

Depending on how many textFields you have in the tableView, the solution could be to create an NSDictionary to keep a reference to the section and row.

1
votes

This is an interesting way of figuring out the indexPath, but a safer way might be to use textView's delegate method and figure out the indexPath of the tableViewCell in relation to the tableView.

class TableViewCell: UITableViewCell {
    @IBOutlet weak var textField: UITextField!
}

class ViewController: UIViewController {
    var indexPath: IndexPath?
    @IBOutlet weak var tableView: UITableView!

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? TableViewCell else { return UITableViewCell() }
        cell.textField.delegate = self
        return cell
    }
}

extension ViewController: UITextFieldDelegate {
    func textFieldDidBeginEditing(_ textField: UITextField) {
         let point = textField.convert(.zero, to: tableView)
         indexPath = tableView.indexPathForRow(at: point)
    }
}
0
votes

These are the alternatives :
1. Find the cell based on point.

func textFieldDidEndEditing(_ sender: UITextField) {
        let tableViewTouchPoint:CGPoint = sender.convert(CGPointZero, to:self.tableView)
        let indexPath = self.tableView.indexPathForRow(at: tableViewTouchPoint)

    }

Create an extension of Tableview for the same by

extension UITableView {

  func indexPathForView(_ view: UIView) -> IndexPath? {
    let tableViewTouchPoint:CGPoint = view.convert(CGPointZero, to:self)
        let indexPath = self.indexPathForRow(at: tableViewTouchPoint)
    return indexPath
  }
}

Use it by

   let indexPath = self.tableView.indexPathForView(textField) 
  1. Based on subview tag. In CellForRowATIndex, set the tags to view equal to indexPath.row. Then, to get back the IndexPath use :

    let index = sender.tag

    let indePath = IndexPath(row: index, section: 0)