Custom button in UITableViewCell – indexPath

Hi all

I am currently working on iPhone app number two when I came across a problem that it has taken me a while to sort out.  I wanted to place a button inside each UITableCell I am displaying.  I then wanted to call a method when the user pressed that button which would perform some action on the information related to the contents of that cell.

For this to be useful I needed to be able to get the indexpath of the row in which the button was pressed.  It took me a while to work this out but I eventually came up with a solution which is really simple, in fact so simple I am angry I did not work it out sooner. Below is the line of code I am using in my button method to get the indexPath.

NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];

The method signature used was:

- (void)buttonMethod:(UIButton *)sender

From this point on I was then able to access the section and row of the cell in which the button was pressed using:

NSInteger section = indexPath.section;
NSInteger row = indexPath.row;

Mike

Share:
  • Digg
  • del.icio.us
  • Facebook
  • MySpace
  • Reddit
  • StumbleUpon
  • Technorati
  • TwitThis
  • Design Float
  • DZone
  • email
  • Google Bookmarks
  • LinkedIn
  • Scoopeo
  • Tumblr

28 Comments

Rajeev  on December 15th, 2008

NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];

please change this statement to

NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[sender superview]];

with this you will get the index path for the cell. But with your previous statement you were getting the table view not the cell index path.

mike  on December 16th, 2008

Thanks for your reply Rajeev.

I am using the code I have provided above within my app and its working fine. I think that [sender superview] will give me the contentView within the cell rather than the cell itself, that is why I am using [[sender superview] superview]. The first superview being the contentView of the cell and the second superview being the cell itself.

If this was giving me the tableView then my app would not be working.

Happy to take more comments on this.

Thanks

Mike

Harsha  on December 24th, 2008

I thank u both a lot…i too needed this information…thanks a lot….[:)]

mike  on December 24th, 2008

Thanks Harsha, happy to help. If you have any questions you like to share feel free to do so. I’ve been working through all sorts recently and I’d be happy to answer any other questions if I can.

Happy Christmas

Mike

Tom  on December 25th, 2008

Mike,

This is timely for me as well. I’ve tried both versions above but I always get a row of 0 when I run this regardless of which row I click.

Any ideas?

Thanks,

Tom

mike  on December 27th, 2008

Hi Tom

Are you able to post the code you are using. I am not sure why you are getting a row back or 0 at the moment. If I can see the methods it may help and I’d be happy to take a look.

Mike

collin  on January 15th, 2009

Thanks, you saved me a lot of headache. This was the first thing that came up on my google search!

Leachy Peachy  on January 17th, 2009

You rock. I was wondering what I was doing wrong. Thanks for the help.

IrvTheSwirv  on February 3rd, 2009

You’ve just saved me a WHOLE load of digging. Cheers for that!

mike  on February 3rd, 2009

Thanks for the feedback and I’m glad it helped :o)

Mike

Benno  on February 27th, 2009

Wow! I tried TONS of different ways to get buttons on each row working but to no avail until i found this. I had the same kind of “I can’t believe I didn’t think of this already!” moment as soon as i saw the crucial line: [[sender superview] superview]

I love the iPhone and i love making apps for it, but it’s horrible hacks like this that make me cry myself to sleep at night.

Thanks so much for your insight though, this programmer will sleep well tonight =D

Joe  on March 18th, 2009

While this works, it is not a good practice. Especially when you have an even deeper view hierarchy in a UITableViewCell or if UITableViewCell’s implementation ever changes (don’t think Apple hasn’t done it before).

The better option is to set the tag of your UIButton to the row that its UITableViewCell is being shown at. You can set the target/action when you create a cell, and set a tag every time you return a cell. In your action method, you can just grab the [sender tag] to get the row the button is in.

Anonymous  on March 19th, 2009

@Joe, thanks for the info. I’m sure I tried doing it with the tag and for some reason was not able to do what I needed, but your point on deeper hierarchies or the implementation changing is valid and so I’ll have to try again using Tag and see how I get on.

Cheers

Mike

Anonymous  on March 19th, 2009

I’ve just remembered the problem I came across, although I think now I would be able to solve it, but back when I had the problem I wanted to get to both the section and the row as the rows could be in different sections. I could just put the row and section into a string in the button Tag with some kind of delimiter and then explode it later, but at the time I found the superview approach first and it worked.

If Apple ever did change the implementation it would come with a new SDK and some work would be required to change how this worked, but for my needs I think I’ll stick with this rather than exploding strings etc.

Mike

Joe  on March 19th, 2009

Here you go: http://weblog.bignerdranch.com/?p=56

And if you using multiple sections, I would be surprised if the buttons in each section didn’t have a different action. In this approach, that works out, because you know which action messages are being sent from which section simply by what they are trying to do. Of course, another approach would be to [button setTag:[indexPath section] * 1000 + [indexPath row], and then you can divide by 1000 to get the section and your row is the remainder. :)

links for 2009-07-03 | manicwave.com  on July 3rd, 2009

[...] 71² » Custom button in UITableViewCell – indexPath NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]]; (tags: iphone uitableview) [...]

Anonymous  on July 21st, 2009

awesome – you saved me :)

Thanks a million!

Mubashir

Ross Nelson  on October 24th, 2009

I spent HOURS trying to get this to work trying everything I could think of until I ran across this post. Works perfectly. Thanks!

mike  on October 25th, 2009

Excellent, I’m glad it helped you out :o)

Mike

Anonymous  on October 30th, 2009

Thanks a million! Still helping people after almost a year, good work.

Anonymous  on December 23rd, 2009

SIMPLY AMAZING!!

I wish I’d found this five hours ago!! ;)

mike  on December 23rd, 2009

LOL, If I had a penny for the number of times I’ve said the same thing on finding a nugget on the net I’d have fewer wrinkles :o)

Glad it helped you out

Mike

JOnSok  on January 30th, 2010

HI I used your example and got the following build error

error: request for member ‘tableView’ in something not a structure or union
any ideas, its driving me crazy

Giova  on February 24th, 2010

GREAAAAT!!!!!!! Thank you man, Awesome and super useful post, really, I’ve browsed so many blogs before findind you!!

Thanks

mike  on February 24th, 2010

Thanks Giova

Mike

Andiih  on April 1st, 2010

Yep. still useful!

Rob  on April 20th, 2010

Hi Mike,
Thanks for the awesome tip!
I’m trying to do the same thing, but I’m getting an error in my TableViewCell subclass for the “NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];” saying that the “Request for member ‘tableView’ in something that is not a structure or union”.
Do I need to pass that down somehow?
Thanks again for getting me one step closer!!

Rob P  on May 8th, 2010

You rock man… super simple and easy to implement!

@Rob above, make sure it is within a uitableviewcontroller and you have setup the dataSource and delegate. The code should be something like this within the parent view controller for that table:

- (void)buttonMethod:(UIButton *)sender {

// method for finding what button was pressed

NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];

NSInteger section = indexPath.section;
NSInteger row = indexPath.row;

NSLog(@”Button is in section %d and row %d”, section, row);

}

and then put this in the .h file

UIButton *buttonMethod;

and

- (void)buttonMethod:(UIButton *)sender;

Leave a Comment