By Vincent


2015-02-22 15:52:30 8 Comments

I have a tableview with buttons and I want to use the indexpath.row when one of them is tapped. This is what I currently have, but it always is 0

var point = Int()
func buttonPressed(sender: AnyObject) {
    let pointInTable: CGPoint =         sender.convertPoint(sender.bounds.origin, toView: self.tableView)
    let cellIndexPath = self.tableView.indexPathForRowAtPoint(pointInTable)
    println(cellIndexPath)
    point = cellIndexPath!.row
    println(point)
}

14 comments

@Paulw11 2016-08-14 10:54:49

My approach to this sort of problem is to use a delegate protocol between the cell and the tableview. This allows you to keep the button handler in the cell subclass, which enables you to assign the touch up action handler to the prototype cell in Interface Builder, while still keeping the button handler logic in the view controller.

It also avoids the potentially fragile approach of navigating the view hierarchy or the use of the tag property, which has issues when cells indexes change (as a result of insertion, deletion or reordering)

CellSubclass.swift

protocol CellSubclassDelegate: class {
    func buttonTapped(cell: CellSubclass)
}

class CellSubclass: UITableViewCell {

@IBOutlet var someButton: UIButton!

weak var delegate: CellSubclassDelegate?

override func prepareForReuse() {
    super.prepareForReuse()
    self.delegate = nil
}

@IBAction func someButtonTapped(sender: UIButton) {
    self.delegate?.buttonTapped(self)
}

ViewController.swift

class MyViewController: UIViewController, CellSubclassDelegate {

    @IBOutlet var tableview: UITableView!

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CellSubclass

        cell.delegate = self

        // Other cell setup

    } 

    //  MARK: CellSubclassDelegate

    func buttonTapped(cell: CellSubclass) {
        guard let indexPath = self.tableView.indexPathForCell(cell) else {
            // Note, this shouldn't happen - how did the user tap on a button that wasn't on screen?
            return
        }

        //  Do whatever you need to do with the indexPath

        print("Button tapped on row \(indexPath.row)")
    }
} 

@Paulw11 2016-10-24 07:09:28

buttonTapped is the delegate function and is in the view controller. In my example, someButtonTapped is the action method in the cell

@EI Captain v2.0 2016-10-24 07:19:47

@paulw11 I got cell has no member buttonTapped in this method @IBAction func someButtonTapped(sender: UIButton) { self.delegate?.buttonTapped(self) }

@Paulw11 2016-10-24 07:22:44

Your cell shouldn't be it's own delegate. The view controller is the delegate

@Paulw11 2016-10-24 07:35:46

Check your code - it should say weak var delegate: FollowingCellDelegate? not weak var delegate: FollowingCell? = nil Also since the delegate is optional there is no need to explicitly assign nil

@bpapa 2017-02-04 12:52:54

This is a pretty good solution (nowhere near as bad as the two currently with more votes, using the tag looking at the superview) but it feels like too much extra code to be adding.

@Robotic Cat 2017-02-04 13:03:10

This is the correct solution and should be the accepted answer. It does not abuse the tag property, does not assume the construction of cells (that can easily be changed by Apple) and will still work (with no extra coding) when cells are moved or new cells added in between existing cells.

@Paulw11 2017-02-04 13:33:00

@bpapa there isn't too much extra code here. You would need to write code to handle the tap anyway, so the "extra" code is 3 lines of protocol definition, 1 line for the delegate property, 1 to set it, 1 to clear it and 1 to invoke it, however I do like the closure answer too.

@bpapa 2017-02-04 14:29:19

Protocol, delegate, complexity, etc. I've always used the "locate the button in the scroll view" method described, 2 lines.

@Adrian 2017-05-18 18:02:06

@Paulw11 I initially thought this was a lot of code, but it's proven a lot more resilient than what I was using before. Thank you for posting this robust solution.

@Karishma 2017-07-13 11:04:50

This is the best solution I have found so far! Thank you so much!

@ymutlu 2018-08-07 07:42:57

This is the correct solution and should be the accepted answer.

@Duncan C 2019-01-27 12:52:11

This is a good clean solution but it requires a lot of setup. I prefer my solution of adding an extension to UITableView. (See my answer.)

@Bhavesh.iosDev 2019-02-06 05:30:59

i think delegate property should be weak otherwise it create retain Cycle.

@Wangdu Lin 2019-08-05 18:32:25

Good answer! Best for me

@Paresh Mangukiya 2018-10-28 04:47:19

I found a very easy and saficiat way to use for manage any cell in tableView and collectionView by using a Model class and this a work as perfectly.

There is indeed a much better way to handle this now. This will work for manage cell and value

here is my output(screenshote) so see this

here is my code

  1. Its very simple to create model clas, please follow the below procedure. Create swift class with name "RNCheckedModel", write the code as below.

class RNCheckedModel: NSObject {

var is_check = false
var user_name = ""

}
  1. create your cell class

class InviteCell: UITableViewCell {

@IBOutlet var imgProfileImage: UIImageView!
@IBOutlet var btnCheck: UIButton!
@IBOutlet var lblName: UILabel!
@IBOutlet var lblEmail: UILabel!
}
  1. and finaly use model class in your UIViewController when you use your UITableView.

class RNInviteVC: UIViewController, UITableViewDelegate, UITableViewDataSource {

@IBOutlet var inviteTableView: UITableView!
@IBOutlet var btnInvite: UIButton!

var checkArray : NSMutableArray = NSMutableArray()
var userName : NSMutableArray = NSMutableArray()

override func viewDidLoad() {
    super.viewDidLoad()
    btnInvite.layer.borderWidth = 1.5
    btnInvite.layer.cornerRadius = btnInvite.frame.height / 2
    btnInvite.layer.borderColor =  hexColor(hex: "#512DA8").cgColor

    var userName1 =["Olivia","Amelia","Emily","Isla","Ava","Lily","Sophia","Ella","Jessica","Mia","Grace","Evie","Sophie","Poppy","Isabella","Charlotte","Freya","Ruby","Daisy","Alice"]


    self.userName.removeAllObjects()
    for items in userName1 {
       print(items)


        let model = RNCheckedModel()
        model.user_name = items
        model.is_check = false
        self.userName.add(model)
    }
  }
 @IBAction func btnInviteClick(_ sender: Any) {

}
   func tableView(_ tableView: UITableView, numberOfRowsInSection 
   section: Int) -> Int {
    return userName.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: InviteCell = inviteTableView.dequeueReusableCell(withIdentifier: "InviteCell", for: indexPath) as! InviteCell

    let image = UIImage(named: "ic_unchecked")
    cell.imgProfileImage.layer.borderWidth = 1.0
    cell.imgProfileImage.layer.masksToBounds = false
    cell.imgProfileImage.layer.borderColor = UIColor.white.cgColor
    cell.imgProfileImage.layer.cornerRadius =  cell.imgProfileImage.frame.size.width / 2
    cell.imgProfileImage.clipsToBounds = true

    let model = self.userName[indexPath.row] as! RNCheckedModel
    cell.lblName.text = model.user_name

    if (model.is_check) {
        cell.btnCheck.setImage(UIImage(named: "ic_checked"), for: UIControlState.normal)
    }
    else {
        cell.btnCheck.setImage(UIImage(named: "ic_unchecked"), for: UIControlState.normal)
    }

    cell.btnCheck.tag = indexPath.row
    cell.btnCheck.addTarget(self, action: #selector(self.btnCheck(_:)), for: .touchUpInside)

    cell.btnCheck.isUserInteractionEnabled = true

return cell

}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 80

}

@objc func btnCheck(_ sender: UIButton) {

    let tag = sender.tag
    let indexPath = IndexPath(row: tag, section: 0)
    let cell: InviteCell = inviteTableView.dequeueReusableCell(withIdentifier: "InviteCell", for: indexPath) as! InviteCell

    let model = self.userName[indexPath.row] as! RNCheckedModel

    if (model.is_check) {

        model.is_check = false
        cell.btnCheck.setImage(UIImage(named: "ic_unchecked"), for: UIControlState.normal)

        checkArray.remove(model.user_name)
        if checkArray.count > 0 {
            btnInvite.setTitle("Invite (\(checkArray.count))", for: .normal)
            print(checkArray.count)
            UIView.performWithoutAnimation {
                self.view.layoutIfNeeded()
            }
        } else {
            btnInvite.setTitle("Invite", for: .normal)
            UIView.performWithoutAnimation {
                self.view.layoutIfNeeded()
            }
        }

    }else {

        model.is_check = true
        cell.btnCheck.setImage(UIImage(named: "ic_checked"), for: UIControlState.normal)

        checkArray.add(model.user_name)
        if checkArray.count > 0 {
            btnInvite.setTitle("Invite (\(checkArray.count))", for: .normal)
            UIView.performWithoutAnimation {
            self.view.layoutIfNeeded()
            }
        } else {
             btnInvite.setTitle("Invite", for: .normal)
        }
    }

    self.inviteTableView.reloadData()
}

func hexColor(hex:String) -> UIColor {
    var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()

    if (cString.hasPrefix("#")) {
        cString.remove(at: cString.startIndex)
    }

    if ((cString.count) != 6) {
        return UIColor.gray
    }

    var rgbValue:UInt32 = 0
    Scanner(string: cString).scanHexInt32(&rgbValue)

    return UIColor(
        red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
        green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
        blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
        alpha: CGFloat(1.0)
    )
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

}

 }

@Iron John Bonney 2016-03-24 20:14:37

UPDATE: Getting the indexPath of the cell containing the button (both section and row):

Using Button Position

Inside of your buttonTapped method, you can grab the button's position, convert it to a coordinate in the tableView, then get the indexPath of the row at that coordinate.

func buttonTapped(_ sender:AnyObject) {
    let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
}

NOTE: Sometimes you can run into an edge case when using the function view.convert(CGPointZero, to:self.tableView) results in finding nil for a row at a point, even though there is a tableView cell there. To fix this, try passing a real coordinate that is slightly offset from the origin, such as:

let buttonPosition:CGPoint = sender.convert(CGPoint.init(x: 5.0, y: 5.0), to:self.tableView)

Previous Answer: Using Tag Property (only returns row)

Rather than climbing into the superview trees to grab a pointer to the cell that holds the UIButton, there is a safer, more repeatable technique utilizing the button.tag property mentioned by Antonio above, described in this answer, and shown below:

In cellForRowAtIndexPath: you set the tag property:

button.tag = indexPath.row
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)

Then, in the buttonClicked: function, you reference that tag to grab the row of the indexPath where the button is located:

func buttonClicked(sender:UIButton) {
    let buttonRow = sender.tag
}

I prefer this method since I've found that swinging in the superview trees can be a risky way to design an app. Also, for objective-C I've used this technique in the past and have been happy with the result.

@Jacob King 2016-04-16 11:22:42

This is a nice way of doing it, and I will upvote it to get your rep started a bit, however the only flaw is it doesn't give access to the indexPath.section if this is also needed. Great answer though!

@Iron John Bonney 2016-04-27 00:17:07

Thanks Jacob! I appreciate the rep karma. If you wanted to get the indexPath.section in addition to the indexPath.row (without resetting the tag property as indexPath.section), in cellForRowAtIndexPath: you could just change the tag to button.tag = indexPath, and then in the buttonClicked: function you could access both by using sender.tag.row and sender.tag.section.

@Jacob King 2016-04-27 17:33:06

Is this a new feature, because I'm sure I remember the tag property being of type Int not type AnyObject, unless that changed in swift 2.3?

@Iron John Bonney 2016-04-27 18:26:24

@JacobKing you're right! My bad I totally spaced when writing that comment and was thinking that tag was type AnyObject. Derp - don't mind me. It would be useful if you could pass the indexPath as a tag though...

@mattyU 2016-06-26 21:04:26

hum this is embarrassing because i spent a lot of time trying to figure it out, but it might be useful for some people : "button" is an @IBOutlet UIButton that has to be created in the TableViewCell. And finally and in cellForRowAtIndexPath : cell?.button.tag = indexPath.row cell?.button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)

@bpapa 2017-02-04 12:49:12

Not really a good approach either. For one thing, it would only work in Table Views where there is a single section.

@Iron John Bonney 2017-02-09 17:36:59

@bpapa That's correct, using the tag property only returns the row, so it only works for a single section. I just updated the answer to provide a way to grab the indexPath, so that you can use it with a multi-section tableView.

@DEEPAK KUMAR 2018-06-13 12:19:56

In Swift 4 , just use this:

func buttonTapped(_ sender: UIButton) {
        let buttonPostion = sender.convert(sender.bounds.origin, to: tableView)

        if let indexPath = tableView.indexPathForRow(at: buttonPostion) {
            let rowIndex =  indexPath.row
        }
}

@10000RubyPools 2018-12-31 21:20:42

Cleanest answer, should be the selected. Only thing to note is that tableView is an outlet variable that needs to be referenced prior before this answer working.

@Parthpatel1105 2019-04-15 09:56:58

Work like charm!!

@Jacob King 2015-04-22 09:18:33

giorashc almost had it with his answer, but he overlooked the fact that cell's have an extra contentView layer. Thus, we have to go one layer deeper:

guard let cell = sender.superview?.superview as? YourCellClassHere else {
    return // or fatalError() or whatever
}

let indexPath = itemTable.indexPath(for: cell)

This is because within the view hierarchy a tableView has cells as subviews which subsequently have their own 'content views' this is why you must get the superview of this content view to get the cell itself. As a result of this, if your button is contained in a subview rather than directly into the cell's content view, you'll have to go however many layers deeper to access it.

The above is one such approach, but not necessarily the best approach. Whilst it is functional, it assumes details about a UITableViewCell that Apple have never necessarily documented, such as it's view hierarchy. This could be changed in the future, and the above code may well behave unpredictably as a result.

As a result of the above, for longevity and reliability reasons, I recommend adopting another approach. There are many alternatives listed in this thread, and I encourage you to read down, but my personal favourite is as follows:

Hold a property of a closure on your cell class, have the button's action method invoke this.

class MyCell: UITableViewCell {
    var button: UIButton!

    var buttonAction: ((Any) -> Void)?

    @objc func buttonPressed(sender: Any) {
        self.buttonAction?(sender)
    }
}

Then, when you create your cell in cellForRowAtIndexPath, you can assign a value to your closure.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! MyCell
    cell.buttonAction = { sender in
        // Do whatever you want from your button here.
    }
    // OR
    cell.buttonAction = buttonPressed(closure: buttonAction, indexPath: indexPath) // <- Method on the view controller to handle button presses.
}

By moving your handler code here, you can take advantage of the already present indexPath argument. This is a much safer approach that the one listed above as it doesn't rely on undocumented traits.

@jaytrixz 2015-12-29 02:04:43

Deleted my answer as it's the same with yours. I suggest an edit to the answer above without the ugly if let statements to let cell = view.superview.superview as! <Your custom cell name here>

@Jacob King 2015-12-29 22:25:17

The if let statements are there to prevent the app from crashing should any of the superviews be nil, this is the correct way to unwrap and should not be considered 'ugly'.

@Jesus Rodriguez 2016-01-28 23:37:58

what is itemTable?

@Jacob King 2016-01-29 09:13:07

itemTable is the name of my previously declared UITableView

@Swayambhu 2016-07-21 08:27:50

indexPathForCell will return type of NSIndexPath. so the var indexPath should not be Int! it should be var indexPath: NSIndexPath!

@Jacob King 2016-07-22 09:18:32

Well spotted. I am a competent developer, I promise ;) - Have amended my answer.

@rmaddy 2017-02-03 18:15:24

This is not the proper way to get the cell from a button. A cell's layout has changed over the years and code like this will fail to work when that happens. Do not use this approach.

@bpapa 2017-02-04 12:47:23

This is a bad solution. It assumes details about UITableViewCells that Apple has never necessarily agreed to. While UITableViewCells have a contentView property there is no guarantee that the contentView's superview will always be the Cell.

@Jacob King 2017-02-06 07:09:18

@bpapa I did make a point of saying this in the answer, it's not like I didn't make the OP aware...

@Pintu Rajput 2017-11-08 08:07:56

if let cell = sender.superview?.superview as? UITableViewCell { } is not working for me.

@Jacob King 2017-11-08 10:08:42

@PintuRajput Can you describe your view hierarchy to me please? You're likely seeing this because your button is not a direct subview of the cell's content view.

@Pintu Rajput 2017-11-08 10:13:38

@JacobKing Done :(

@Erick Maynard 2018-02-13 02:42:35

This solution also assumes the button pressed isn't nested within any other views.

@CW0007007 2018-05-09 12:52:49

Traversing superviews is a very bad idea.

@ymutlu 2018-08-07 07:44:27

This answer is like a joke. You should not use superview to reach parent views. This could break with any minor update in view hierarchy

@Jacob King 2018-08-08 00:10:17

@ymutlu I totally agree, I did state this in the answer. I also proposed a much more robust solution. The reason I left the original in place is because I feel it's better to show other devs the issues with an approach than dodge it altogether, this teaches them nothing you see. :)

@ymutlu 2018-08-08 07:42:54

@JacobKing 👍You are right.

@Vineeth Krishnan 2018-03-13 07:20:44

Try using #selector to call the IBaction.In the cellforrowatindexpath

            cell.editButton.tag = indexPath.row
        cell.editButton.addTarget(self, action: #selector(editButtonPressed), for: .touchUpInside)

This way you can access the indexpath inside the method editButtonPressed

func editButtonPressed(_ sender: UIButton) {

print(sender.tag)//this value will be same as indexpath.row

}

@Amalendu Kar 2019-04-15 05:19:05

Most appropriate answer

@Duncan C 2017-02-04 17:23:37

Use an extension to UITableView to fetch the cell for any view:


@Paulw11's answer of setting up a custom cell type with a delegate property that sends messages to the table view is a good way to go, but it requires a certain amount of work to set up.

I think walking the table view cell's view hierarchy looking for the cell is a bad idea. It is fragile - if you later enclose your button in a view for layout purposes, that code is likely to break.

Using view tags is also fragile. You have to remember to set up the tags when you create the cell, and if you use that approach in a view controller that uses view tags for another purpose you can have duplicate tag numbers and your code can fail to work as expected.

I have created an extension to UITableView that lets you get the indexPath for any view that is contained in a table view cell. It returns an Optional that will be nil if the view passed in actually does not fall within a table view cell. Below is the extension source file in it's entirety. You can simply put this file in your project and then use the included indexPathForView(_:) method to find the indexPath that contains any view.

//
//  UITableView+indexPathForView.swift
//  TableViewExtension
//
//  Created by Duncan Champney on 12/23/16.
//  Copyright © 2016-2017 Duncan Champney.
//  May be used freely in for any purpose as long as this 
//  copyright notice is included.

import UIKit

public extension UITableView {

  /**
  This method returns the indexPath of the cell that contains the specified view

   - Parameter view: The view to find.

   - Returns: The indexPath of the cell containing the view, or nil if it can't be found

  */

    func indexPathForView(_ view: UIView) -> IndexPath? {
        let center = view.center
        let viewCenter = self.convert(center, from: view.superview)
        let indexPath = self.indexPathForRow(at: viewCenter)
        return indexPath
    }
}

To use it, you can simply call the method in the IBAction for a button that's contained in a cell:

func buttonTapped(_ button: UIButton) {
  if let indexPath = self.tableView.indexPathForView(button) {
    print("Button tapped at indexPath \(indexPath)")
  }
  else {
    print("Button indexPath not found")
  }
}

(Note that the indexPathForView(_:) function will only work if the view object it's passed is contained by a cell that's currently on-screen. That's reasonable, since a view that is not on-screen doesn't actually belong to a specific indexPath; it's likely to be assigned to a different indexPath when it's containing cell is recycled.)

EDIT:

You can download a working demo project that uses the above extension from Github: TableViewExtension.git

@Jeremy Andrews 2017-10-29 13:54:47

Thanks I used the extension to get the indexPath of a textview in a cell - worked perfectly.

@Joseph Mikko Manoza 2018-02-07 09:56:53

thanks it's works.

@Sajid Zeb 2018-02-24 13:01:05

Swift 4 Solution:

You have a button (myButton) or any other view in cell. Assign tag in cellForRowAt like this

cell.myButton.tag = indexPath.row

Now in you tapFunction or any other. Fetch it out like this and save it in a local variable.

currentCellNumber = (sender.view?.tag)!

After this you can use anywhere this currentCellNumber to get the indexPath.row of selected button.

Enjoy!

@Teena nath Paul 2017-02-17 07:03:02

Sometimes button may be inside of another view of UITableViewCell. In that case superview.superview may not give the cell object and hence the indexPath will be nil.

In that case we should keep finding the superview until we get the cell object.

Function to get cell object by superview

func getCellForView(view:UIView) -> UITableViewCell?
{
    var superView = view.superview

    while superView != nil
    {
        if superView is UITableViewCell
        {
            return superView as? UITableViewCell
        }
        else
        {
            superView = superView?.superview
        }
    }

    return nil
}

Now we can get indexPath on button tap as below

@IBAction func tapButton(_ sender: UIButton)
{
    let cell = getCellForView(view: sender)
    let indexPath = myTabelView.indexPath(for: cell)
}

@sean 2017-01-25 03:17:37

In Swift 3. Also used guard statements, avoiding a long chain of braces.

func buttonTapped(sender: UIButton) {
    guard let cellInAction = sender.superview as? UITableViewCell else { return }
    guard let indexPath = tableView?.indexPath(for: cellInAction) else { return }

    print(indexPath)
}

@rmaddy 2017-02-03 18:16:43

This will not work. The button's superview will not be the cell.

@sean 2017-02-10 17:17:12

This does work. The only thing you should be carefully of is that everyone's view stack is different. It could be sender.superview, sender.superview.superview or sender.superview.superview.superview. But it works really well.

@Jacob King 2016-09-26 12:18:04

After seeing Paulw11's suggestion of using a delegate callback, I wanted to elaborate on it slightly/put forward another, similar suggestion. Should you not want to use the delegate pattern you can utilise closures in swift as follows:

Your cell class:

class Cell: UITableViewCell {
    @IBOutlet var button: UIButton!

    var buttonAction: ((sender: AnyObject) -> Void)?

    @IBAction func buttonPressed(sender: AnyObject) {
        self.buttonAction?(sender)
    }
}

Your cellForRowAtIndexPath method:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
    cell.buttonAction = { (sender) in
        // Do whatever you want from your button here.
    }
    // OR
    cell.buttonAction = buttonPressed // <- Method on the view controller to handle button presses.
}

@fs_tigre 2019-03-25 23:47:44

This worked for me. Thanks.

@specialvict 2016-02-22 05:40:48

For Swift2.1

I found a way to do it, hopefully, it'll help.

let point = tableView.convertPoint(CGPoint.zero, fromView: sender)

    guard let indexPath = tableView.indexPathForRowAtPoint(point) else {
        fatalError("can't find point in tableView")
    }

@OOProg 2016-07-25 16:38:15

What does it mean if the error runs? What are some reasons why it can't find the point in the tableView?

@bpapa 2017-02-04 12:55:46

This (or similar, using the UIView Converting methods) should be the accepted answer. Not sure why it's currently #4, as it doesn't make assumptions about a table view's private heirarchy, it doesn't use the tag property (almost always a bad idea), and doesn't involve a lot of extra code.

@Avijit Nagare 2016-02-07 04:53:42

I used convertPoint method to get point from tableview and pass this point to indexPathForRowAtPoint method to get indexPath

 @IBAction func newsButtonAction(sender: UIButton) {
        let buttonPosition = sender.convertPoint(CGPointZero, toView: self.newsTableView)
        let indexPath = self.newsTableView.indexPathForRowAtPoint(buttonPosition)
        if indexPath != nil {
            if indexPath?.row == 1{
                self.performSegueWithIdentifier("alertViewController", sender: self);
            }   
        }
    }

@Antonio 2015-02-22 19:29:19

Since the sender of the event handler is the button itself, I'd use the button's tag property to store the index, initialized in cellForRowAtIndexPath.

But with a little more work I'd do in a completely different way. If you are using a custom cell, this is how I would approach the problem:

  • 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

@Dave G 2015-08-18 08:18:33

Antonio, I have a custom cell and would love to do this your way. However, it is not working. I want my 'swipe to reveal delete button' code to run, which is the tableView commitEditingStyle method. I removed that code from the mainVC class and put it in the customCell class, but now the code no longer works. What am I missing?

@Edward 2017-04-26 12:16:23

I think this is the best way to get the indexPath of a cell with x sections, however I don't see the need for bullet points 3 and 4 in a MVC approach

Related Questions

Sponsored Content

31 Answered Questions

[SOLVED] How to create an HTML button that acts like a link?

9 Answered Questions

[SOLVED] How to disable an Android button?

26 Answered Questions

[SOLVED] Trigger a button click with JavaScript on the Enter key in a text box

1 Answered Questions

[SOLVED] Hide button in another cell when cell is tapped

  • 2018-09-21 20:39:51
  • Neccer
  • 28 View
  • -1 Score
  • 1 Answer
  • Tags:   swift uitableview

2 Answered Questions

[SOLVED] Access indexPath.row in button function Swift

2 Answered Questions

[SOLVED] Expand and contract tableview cell when tapped, in swift

  • 2015-08-04 19:57:46
  • Diego Petrucci
  • 17928 View
  • 12 Score
  • 2 Answer
  • Tags:   swift uitableview

4 Answered Questions

[SOLVED] How to get the indexpath.row when a UIImageView in a cell is tapped?

2 Answered Questions

2 Answered Questions

[SOLVED] Get indexPath.row of a cell

Sponsored Content