I have a tableView dynamically populated with custom cells in several sections.
In my CustomCell class I have an @IBAction for a custom checkbox button in the cell.
I have recently come with a solution to this problem leveraging the use of Segues and implementing it in Swift 2.2 and XCode8.
I have a Custom Cell that I'm using for a header that has 2 Labels and a UIButton. All of my data is in an array and I want to dynamically access the data. Each section is an array of section headers and within that class the sections contain additional arrays to finish generating my tableView. My goal was to get the Index of the section based on a button click in the custom cell (header) and change the data in a different view.
To populate the tableView with my custom header cells I used:
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let myCell = tableView.dequeueReusableCellWithIdentifier("REUSABLE ID")! as! MyHeaderCell
let team = array[section]
myCell.teamName.text = team.name
myCell.projectName.text = team.project
myCell.addMemberButton.tag = section
return myCell
}
Using the storyboard, the IBOutlet for the button (addMemberButton) in MyHeaderCell had the .tag field which I used to save the section index. So when I prepared segue I could use this value to dynamically access my array in the DataSource. As follows
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segue1" {
...
}else if segue.identifier == "AddMemberSegue"{
let ix = sender?.tag
let destVC = segue.destinationViewController as! AddMemberViewController
self.myArray = array[ix!]
destVC.delegate = self
}else if segue.identifier == "segue3"{
...
}
}
Here the sender is the button, so the .tag field gives us the specific section index to access the correct location in the array
Hope this helps someone.
One of the ways, suppose you have custom cell and button inside a cell ... Usual pattern would be: (if you're using table view with datasource) when configuring the cell inside:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
you can set:
cell.button.tag = sectionIndex
So in:
func checkboxButton(sender: CheckBox) { ...
sender.tag would be sectionIndex
Hope you got the idea.
For find indexPath in Swift 4 and Swift 5 when calling button,
// First you Add target on button in "cellForRowAt"
cell.myBtn.addTarget(self, action: #selector(self.btnAction(_:)), for: .touchUpInside)
// Add function
func btnAction(_ sender: UIButton) {
let point = sender.convert(CGPoint.zero, to: yourTableView as UIView)
let indexPath: IndexPath! = yourTableView.indexPathForRow(at: point)
print("indexPath.row is = \(indexPath.row) && indexPath.section is = \(indexPath.section)")
}
In Swift 3.0, some things are slightly changed like 'CGPointZero' - > 'CGPoint.zero' & 'indexPathForRowAtPoint' -> 'indexPathForRow(at:position)'
etc so you can get the real row and section of the tapped button from this code:
let position: CGPoint = sender.convert(CGPoint.zero, to: self.tableView)
if let indexPath = self.tableView.indexPathForRow(at: position)
{
let section = indexPath.section
let row = indexPath.row
}
You can easily find the row by calculating the position of the sender and finding the row at that position in the UITableView
var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
if let indexPath = self.tableView.indexPathForRowAtPoint(position)
{
let section = indexPath.section
let row = indexPath.row
}
This is how Apple does it in the Accessory sample. https://developer.apple.com/library/ios/samplecode/Accessory/Listings/AccessoryViewController_m.html#//apple_ref/doc/uid/DTS40008066-AccessoryViewController_m-DontLinkElementID_4