Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIButton action in table view cell

I am trying to run an action for a button being pressed within a table view cell. The following code is in my table view controller class.

The button has been described as "yes" in an outlet in my class of UITableViewCell called requestsCell.

I am using Parse to save data and would like to update an object when the button is pressed. My objectIds array works fine, the cell.yes.tag also prints the correct number to the logs, however, I cannot get that number into my "connected" function in order to run my query properly.

I need a way to get the indexPath.row of the cell to find the proper objectId.

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {     let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as requestsCell      // Configure the cell...      cell.name.text = requested[indexPath.row]      imageFiles[indexPath.row].getDataInBackgroundWithBlock{         (imageData: NSData!, error: NSError!) -> Void in          if error == nil {              let image = UIImage(data: imageData)              cell.userImage.image = image         }else{             println("not working")         }         }      cell.yes.tag = indexPath.row     cell.yes.targetForAction("connected", withSender: self)      println(cell.yes.tag)      return cell }   func connected(sender: UIButton!) {      var query = PFQuery(className:"Contacts")     query.getObjectInBackgroundWithId(objectIDs[sender.tag]) {         (gameScore: PFObject!, error: NSError!) -> Void in         if error != nil {             NSLog("%@", error)         } else {             gameScore["connected"] = "yes"             gameScore.save()         }     }  } 
like image 905
Sammmmm Avatar asked Mar 06 '15 08:03

Sammmmm


People also ask

How do you get the indexPath row when a button in a cell is tapped?

add an 'indexPath` property to the custom table cell. initialize it in cellForRowAtIndexPath. move the tap handler from the view controller to the cell implementation. use the delegation pattern to notify the view controller about the tap event, passing the index path.

What is Table View delegate?

The tableview delegate methods are defined to add the following features to the tableview. We can create the custom headers and footers for the sections in the tableview. We can specify the custom heights for rows, headers, and footers. Provide height estimates for the rows, headers, and footers.


2 Answers

Swift 4 & Swift 5:

You need to add target for that button.

myButton.addTarget(self, action: #selector(connected(sender:)), for: .touchUpInside) 

And of course you need to set tag of that button since you are using it.

myButton.tag = indexPath.row 

You can achieve this by subclassing UITableViewCell. Use it in interface builder, drop a button on that cell, connect it via outlet and there you go.

To get the tag in the connected function:

@objc func connected(sender: UIButton){     let buttonTag = sender.tag } 
like image 163
IxPaka Avatar answered Sep 21 '22 07:09

IxPaka


The accepted answer using button.tag as information carrier which button has actually been pressed is solid and widely accepted but rather limited since a tag can only hold Ints.

You can make use of Swift's awesome closure-capabilities to have greater flexibility and cleaner code.

I recommend this article: How to properly do buttons in table view cells using Swift closures by Jure Zove.

Applied to your problem:

  1. Declare a variable that can hold a closure in your tableview cell like

    var buttonTappedAction : ((UITableViewCell) -> Void)? 
  2. Add an action when the button is pressed that only executes the closure. You did it programmatically with cell.yes.targetForAction("connected", withSender: self) but I would prefer an @IBAction outlet :-)

    @IBAction func buttonTap(sender: AnyObject) {    tapAction?(self) } 
  3. Now pass the content of func connected(sender: UIButton!) { ... } as a closure to cell.tapAction = {<closure content here...>}. Please refer to the article for a more precise explanation and please don't forget to break reference cycles when capturing variables from the environment.
like image 33
Benedikt Reichert Avatar answered Sep 21 '22 07:09

Benedikt Reichert