Reputation: 83
The code below correctly returns the cell:
func findSuperView(sender:UIButton!) -> UITableViewCell {
var superView : UIView? = sender.superview
var foundSuperView : UITableViewCell!
while superView != nil && foundSuperView == nil {
if let cell = superView as? UITableViewCell {
foundSuperView = cell
break
}
else {
superView = superView?.superview
}
}
return foundSuperView
}
But for finding indexpath in tableview it crashes:
var indexPath : NSIndexPath = self.table .indexPathForCell(findSuperView(sender))!
println("Section (indexPath)")
And I tried another way, but it was not successful:
var button : UIButton = sender as UIButton;
var touch: UITouch = events .allTouches()?.anyObject() as UITouch
var location : CGPoint = touch.locationInView(self.table)
var indexPath : NSIndexPath = self.table.indexPathForRowAtPoint(location)!
Upvotes: 3
Views: 3817
Reputation: 21
This code works fine for Swift 5:
private func onTapButtonInsideCell(button: UIButton, event: UIEvent) {
guard let touches = event.touches(for: button), !touches.isEmpty else {
return
}
let touch = touches[touches.startIndex]
let point = touch.location(in: tableView)
guard let indexPath = tableView.indexPathForItem(at: point) else {
return
}
print("onTapButtonInsideCell() indexPath.row=\(indexPath.row)")
}
Github Gist: https://gist.github.com/rsaenzi/13dc00b5cb5a09efa84eaff3ff4682af
Upvotes: 0
Reputation: 3143
If you're using a custom tableViewCell (which you probably are) you can just create a variable.
class Cell: UITableViewCell {
var id = ""
@IBAction func buttonPressed(sender: AnyObject) {
print(id) // Can also call a function with 'id' as a parameter
}
}
And:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: Cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
cell.id = indexPath.row // Or however you wan't to give it an Id
return cell
}
Upvotes: 0
Reputation: 154711
You seem to be having trouble finding the tableView
from your code which handles the @IBAction
for your button.
You could create a UIButton
subclass that keeps track of both the cell
the button is in and the UITableView
that the cell is contained in. Then it is a simple matter of calling tableView:indexPathForCell
in the @IBAction
for the button.
MyButton.swift:
class MyButton: UIButton {
weak var myTable: UITableView?
weak var myCell: UITableViewCell?
}
CustomTableViewCell.swift:
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var myButton: MyButton!
@IBAction func whereAmI(button: MyButton) {
if let myCell = button.myCell, indexPath = button.myTable?.indexPathForCell(myCell) {
print("I am in row \(indexPath.row)")
}
}
}
In TableViewController.swift:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomTableViewCell
cell.myButton.myCell = cell
cell.myButton.myTable = tableView
// Other cell setup
return cell
}
To make this work, it is important to set the classes for the UIButton
and the UITableViewCell
to MyButton
and CustomTableViewCell
in the Identity Inspector. Also, wire the button to its @IBOutlet
in CustomTableViewCell.swift
.
Upvotes: 1
Reputation: 154711
I don't know if there is an easy a way to do this. (Edit: Actually there is. Look at @mustafa's second solution.) A workaround is to set the button's tag to indexPath.row
in cellForRowAtIndexPath
, then you can just access the button's tag to find out which row it belongs to.
Warning: This workaround is fragile. It won't work correctly if you allow rows to be added or deleted from your table without then calling tableView.reloadData()
. Look at @mustafa's solution which is much more robust.
Upvotes: -1
Reputation: 15464
Here is a candidate action method for your button's TouchUpInside
event.
func someAction(sender:UIButton, event: UIEvent) {
if let touch = event.touchesForView(sender)?.anyObject() as? UITouch {
let point = touch.locationInView(tableView)
if let indexPath = tableView.indexPathForRowAtPoint(point) {
// Do something with indexPath
}
}
}
And here is another one:
func someAction(sender: UIButton) {
let point = tableView.convertPoint(CGPointZero, fromView: sender)
if let indexPath = tableView.indexPathForRowAtPoint(point) {
// Do something with indexPath
}
}
Upvotes: 10
Reputation: 42598
There is an issue with func findSuperView(sender:UIButton!) -> UITableViewCell
. Nothing ensures foundSuperView
will have a value.
func findSuperView(sender:UIButton!) -> UITableViewCell {
var superView : UIView? = sender.superview
var foundSuperView : UITableViewCell! // NOTE: The value is nil.
while superView != nil && foundSuperView == nil {
if let cell = superView as? UITableViewCell {
foundSuperView = cell
break
}
else {
superView = superView?.superview
}
}
return foundSuperView // NOTE: This will crash if foundSuperView == nil
}
A safer way of finding the super cell of a view is returning an optional.
func findSuperCellOfView(view: UIView?) -> UITableViewCell? {
if view == nil {
return nil
} else if let cell = view as? UITableViewCell {
return cell
} else {
return findSuperCellOfView(view?.superview)
}
}
Which would be used as follows.
if let cell = findSuperCellOfView(button) {
let indexPath = table.indexPathForCell(cell)
println("Section \(indexPath)")
}
Upvotes: 0