Lester
Lester

Reputation: 741

Detect UIButton while using custom UITableViewCell

I want to implement a custom UITableViewCell class that is made up of subviews such as, labels, buttons, and images. These cells will display content fetched from the web using an API.

I do not want to implement the UITableView delegate method didSelectRowAtIndexPath as this will make the entire cell selectable. Only the button in the cell should be able to trigger any action.

The button is connected from the storyboard to the custom UITableViewCell via IBOutlet. The addTarget(_:action:forControlEvents:) method is called on the UIButton in cellForRowAtIndexPath of the UITableViewController class.

The roadblock occurs when we want to detect the indexPath of the selected cell in the Selector function of the button.

This is how the indexPath for the selected cell can be detected in the Selector function

@IBAction func doSomething(sender: AnyObject) {
    var location: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
    var indexPath: NSIndexPath = self.tableView.indexPathForRowAtPoint(location)!
    println("The indexPath for Selected Cell is - \(indexPath.row)")
}

Although, this successfully gets me around the issue, my question is;

1) Have you found an alternate way of being able to use UIButtons to pass selected cell data in a custom UITableViewCell?

2) What would be the best practice, so far, in Swift to implement a similar scenario?

Upvotes: 1

Views: 972

Answers (2)

vacawama
vacawama

Reputation: 154593

If your tableView only has one section, you can use the tag property of the button to store the indexPath.row.

In cellForRowAtIndexPath, when you set the target-action for the button, set button.tag = indexPath.row.

Then in your doSomething routine:

@IBAction doSomething(sender: UIButton) {
    println("This button is from row - \(sender.tag)")
}

Upvotes: 1

Jawwad
Jawwad

Reputation: 1336

One way would be to iterate over the superviews of the sender and see if a UITableViewCell can be found...

Let's say you created a generic UIView extension with a method that would check to see if any of its superview's was a UITableViewCell...

extension UIView {
    func parentTableViewCell() -> UITableViewCell? {
        var view = self
        while let superview = view.superview {
            if let cell = superview as? UITableViewCell {
                return cell
            } else {
                view = superview
            }
        }
        return nil
    }
}

Then you could do the following...

if let cell = (sender as UIView).parentTableViewCell() {
    let indexPath = tableView.indexPathForCell(cell)
    println("The row for this cell is - \(indexPath.row)")
}

Another way would be to use the tag property of a view by setting it to an Int and then check to see what the tag of the sender was in the method.

i.e. In your tableView:cellForRowAtIndexPath: method

cell.myButton.tag = indexPath.row

Then in your doSomething method

let rowIndex = (sender as UIButton).tag
println("The row for this cell is - \(rowIndex)"

Upvotes: 2

Related Questions