How to access the content of a custom cell in swift using button tag?
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
.
Related videos on Youtube
![Steve Rowe](https://lh3.googleusercontent.com/-S1mGWQhCRtI/AAAAAAAAAAI/AAAAAAAAADI/V84zUV42QJg/photo.jpg?sz=256)
Steve Rowe
Updated on June 12, 2022Comments
-
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 about 9 yearsI 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 about 9 yearsOf course I should have, my bad. Will edit it. Thanks.
-
Steve Rowe about 9 yearsThanks so much guys. It works like a charm and has given me a little insight into delegate.. still very much a newbie.
-
Steve Rowe about 9 yearsI 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 about 9 yearsWhat 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 about 9 yearsI 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 about 9 yearsOK, I will edit my answer. Note that I am not on my Mac and I can't test the code.
-
Steve Rowe about 9 yearsThanks so much. You are a star. It worked perfectly.
-
seggy over 7 years@flashadvanced thank you so much its worked perfectly.. but how i change image of button using option 2 ?
-
Akhilesh Sharma over 7 yearsI 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 almost 7 yearsit 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...