How to access the content of a custom cell in swift using button tag?

49,288

Solution 1

OPTION 1. Handling it with delegation

The right way of handling events fired from your cell's subviews is to use delegation.

So you can follow the steps:

1. Above your class definition write a protocol with a single instance method inside your custom cell:

protocol CustomCellDelegate {
    func cellButtonTapped(cell: CustomCell)
} 

2. Inside your class definition declare a delegate variable and call the protocol method on the delegate:

var delegate: CustomCellDelegate?

@IBAction func buttonTapped(sender: AnyObject) {
    delegate?.cellButtonTapped(self)
}

3. Conform to the CustomCellDelegate in the class where your table view is:

 class ViewController: CustomCellDelegate

4. Set your cell's delegate

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as CustomCell
    cell.delegate = self

    return cell
}

5. Implement the required method in your view controller class.

EDIT: First define an empty array and then modify it like this:

private var selectedItems = [String]()

func cellButtonTapped(cell: CustomCell) {
    let indexPath = self.tableView.indexPathForRowAtPoint(cell.center)!
    let selectedItem = items[indexPath.row]

    if let selectedItemIndex = find(selectedItems, selectedItem) {
        selectedItems.removeAtIndex(selectedItemIndex)
    } else {
        selectedItems.append(selectedItem)
    }
}

where items is an array defined in my view controller:

private let items = ["Dog", "Cat", "Elephant", "Fox", "Ant", "Dolphin", "Donkey", "Horse", "Frog", "Cow", "Goose", "Turtle", "Sheep"] 

OPTION 2. Handling it using closures

I've decided to come back and show you another way of handling these type of situations. Using a closure in this case will result in less code and you'll achieve your goal.

1. Declare a closure variable inside your cell class:

var tapped: ((CustomCell) -> Void)?

2. Invoke the closure inside your button handler.

@IBAction func buttonTapped(sender: AnyObject) {
    tapped?(self)
}

3. In tableView(_:cellForRowAtIndexPath:) in the containing view controller class :

let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell       
cell.tapped = { [unowned self] (selectedCell) -> Void in
    let path = tableView.indexPathForRowAtPoint(selectedCell.center)!
    let selectedItem = self.items[path.row]

    println("the selected item is \(selectedItem)")
}

Solution 2

Since you have 1 section in the table view you can get the cell object as below.

let indexPath = NSIndexPath(forRow: tag, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomCell!

where tag you will get from button tag.

Solution 3

Swift 3 I just get solution for access cell in @IBAction function using superview of button tag.

let cell = sender.superview?.superview as! ProductCell
var intQty = Int(cell.txtQty.text!);
intQty = intQty! + 1
let  strQty = String(describing: intQty!);
cell.txtQty.text = strQty

Solution 4

@IBAction func buttonTap(sender: UIButton) {
        let button = sender as UIButton
        let indexPath = self.tableView.indexPathForRowAtPoint(sender.center)!
}

Solution 5

I updated option 1 of the answer from Vasil Garov for Swift 3

1. Create a protocol for your CustomCell:

protocol CustomCellDelegate {
    func cellButtonTapped(cell: CustomCell)
} 

2. For your TableViewCell declare a delegate variable and call the protocol method on it:

var delegate: CustomCellDelegate?

@IBAction func buttonTapped(sender: AnyObject) {
    delegate?.cellButtonTapped(self)
}

3. Conform to the CustomCellDelegate in the class where your tableView is:

 class ViewController: CustomCellDelegate

4. Set your cell's delegate

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)  as CustomCell
    cell.delegate = self

    return cell
}

5. Implement the required method in your ViewController.

Share:
49,288

Related videos on Youtube

Steve Rowe
Author by

Steve Rowe

Updated on June 12, 2022

Comments

  • Steve Rowe
    Steve Rowe about 2 years

    I have an app that has a custom button in a custom cell. If you select the cell it segues to the a detail view, which is perfect. If I select a button in a cell, the code below prints the cell index into the console.

    I need to access the contents of the selected cell (Using the button) and add them to an array or dictionary. I am new to this so struggling to find out how to access the contents of the cell. I tried using didselectrowatindexpath, but I don't know how to force the index to be that of the tag...

    So basically, if there are 3 cells with 'Dog', 'Cat', 'Bird' as the cell.repeatLabel.text in each cell and I select the buttons in the rows 1 and 3 (Index 0 and 2), it should add 'Dog' and 'Bird' to the array/dictionary.

        // MARK: - Table View
    
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return postsCollection.count
    }
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
        let cell: CustomCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
    
        // Configure the cell...
        var currentRepeat = postsCollection[indexPath.row]
        cell.repeatLabel?.text = currentRepeat.product
        cell.repeatCount?.text = "Repeat: " + String(currentRepeat.currentrepeat) + " of " + String(currentRepeat.totalrepeat)
    
        cell.accessoryType = UITableViewCellAccessoryType.DetailDisclosureButton
    
        cell.checkButton.tag = indexPath.row;
    
        cell.checkButton.addTarget(self, action: Selector("selectItem:"), forControlEvents: UIControlEvents.TouchUpInside)
    
    
        return cell
    
    }
    
    func selectItem(sender:UIButton){
    
        println("Selected item in row \(sender.tag)")
    
     }
    
  • Andrew Robinson
    Andrew Robinson about 9 years
    I like this solution better than the one above. Though, you forgot to mention that he has to actually set the delegate. Other than that the solution is solid.
  • Vasil Garov
    Vasil Garov about 9 years
    Of course I should have, my bad. Will edit it. Thanks.
  • Steve Rowe
    Steve Rowe about 9 years
    Thanks so much guys. It works like a charm and has given me a little insight into delegate.. still very much a newbie.
  • Steve Rowe
    Steve Rowe about 9 years
    I know I am pushing it now but I have been going around in circles.. I need to be able to add the selectedItem to an array and I have no idea how. I've tried adding it to the cellButtonTapped fund, but that doesn't work. If I select something, it must add it to the array, if I unselect it, it must remove it from the array. The idea is that once I have the array I am going to post the results of the selected items to a mySQL database when the user clicks a 'Send' button...
  • Vasil Garov
    Vasil Garov about 9 years
    What did you try in cellButtonTapped ? And what is the expected behavior exactly - tapping the button -> add item to the array, tapping it again -> remove item from the array?
  • Steve Rowe
    Steve Rowe about 9 years
    I tried something like var selectedItems : [String] = String and then appending each selection to the array. This just adds the currently selected item to the array. What you described is exactly what I need it to do. To get the initial data from the mySQL database I have Post class (with JSON) that gets used to create the array postCollection. I suppose I need to create the reverse of that to get to the point where I can send what was selected back to the mySQL database..
  • Vasil Garov
    Vasil Garov about 9 years
    OK, I will edit my answer. Note that I am not on my Mac and I can't test the code.
  • Steve Rowe
    Steve Rowe about 9 years
    Thanks so much. You are a star. It worked perfectly.
  • seggy
    seggy over 7 years
    @flashadvanced thank you so much its worked perfectly.. but how i change image of button using option 2 ?
  • Akhilesh Sharma
    Akhilesh Sharma over 7 years
    I have used a variable in custom cell class,if i alter the variable on button action using delegate method on another view, than how do i get the reflected value of that variable in cellforitem.
  • Jay Patel
    Jay Patel almost 7 years
    it will not work everytime even if its one section.suppose you deleted one cell from tableview and if you access tag as indexPath it will give you wrong index.so beware of that...