Custom UITableView Cell with UIButton not Calling didSelectRowAtIndexPath - ios

I understand this is suppose to happen but I haven't been able to find a way to call this method when the button is tapped The method gets called but the wrong cell is selected.
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object{
_postCell = (postCell *) [self.tableView dequeueReusableCellWithIdentifier:#"postCell"];
_postCell.personStringPost.text = [object objectForKey:#"stringPost"];
[_postCell.nameLabel setTitle:[object objectForKey:#"User_Name"] forState:UIControlStateNormal];
_postCell.userId = [object objectForKey:#"userId"];
_postCell.selectionStyle = UITableViewCellSelectionStyleNone;
PFFile *imageFile = [object objectForKey:#"profileImage"];
NSData *data = [imageFile getData];
_postCell.profileImage.image = [UIImage imageWithData:data];
[_postCell.nameLabel addTarget:self action:#selector(personProfile:tableView:) forControlEvents: UIControlEventTouchUpInside];
[_postCell.profileImageButton addTarget:self action:#selector(personProfile:tableView:) forControlEvents:UIControlEventTouchUpInside];
return _postCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
postCell *cell = (postCell *)[tableView cellForRowAtIndexPath:indexPath];
self.userId = cell.userId;
NSLog(#"Did Select: %#", self.userId);
}
- (void) personProfile: (NSIndexPath *) indexPath tableView: (UITableView *) tableView{
[self tableView:tableView didSelectRowAtIndexPath:indexPath];
[self performSegueWithIdentifier:#"personProfile" sender:self];
}

Few things i hope it will help
while dealing with button with only one section
in cellfor row method
yourcell.mybutton.tag=indexPath.row;
-(void)myCellbuttonAction:(id)sender
{
UIButton *button = (UIButton *)sender; // first, cast the sender to UIButton
NSInteger row = button.tag; // recover the row
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
// apply your logic for indexpath as in didselect row
}
While dealing with multiple sections and multiple rows it this might help you
in cell for row method
yourcell.tag=indexPath.section;
yourcell.contentview.tag=indexPath.row;
and your button action might look like this
-(void)myCellbuttonAction:(id)sender
{
UIButton *button = (UIButton *)sender; // first, cast the sender to UIButton
id rowid =[button superview];
id sectionid = [rwoid superview];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[rowid tag] inSection:[sectionid tag]];
// apply your logic for indexpath as in didselect row
}

A few things here.
a) I would not use an instance variable (_postCell) in your cellForRowAtIndex method. You will likely have cell re-use problems and this may well be the source of your error. Replace it with a local variable:
postcell *cell = (postCell *)[self.tableView dequeueReusableCellWithIdentifier:#"postCell"];
You will also need to replace all references to _postCell with cell.
b) Note that in the same line your cast uses lowercase = (postCell *)... - I have done the same above, but it is best practice for class names to start with capital letters.
c) You have a property named nameLabel, which suggests its a UILabel, but you are using the setTitle:forState: method, which implies it's a UIButton. I would rename this property since debugging will be a lot easier if the names match the classes (or at least don't imply the wrong class).
d) When you call the addTarget:action:forControlEvents method, your selector is for personProfile:tableView:. The signature for that method is for an NSIndexPath and a UITableView. But your button will not be sending those arguments of those types. It will send details of the sender - i.e. the button which triggered the action. So you need to revise your method to accept arguments of that type:
[cell.nameLabel addTarget:self action:#selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];
e) When the method gets called, you need a way to determine which cell the sending button was on. Ideally you would subclass UIButton to add some link to the cell, but (if you have only one section) you might get away with putting the row number as a tag. To do this add:
cell.nameLabel.tag = indexPath.row;
to your cellForRowAtIndexPath:. Then you can implement a different method to handle the button press, as follows:
-(void)buttonPressed:(id)sender {
UIButton *button = (UIButton *)sender; // first, cast the sender to UIButton
NSInteger row = button.tag; // recover the row
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0]; // derive the indexPath, assuming section is 0
[self.tableView selectRowAtIndexPath:indexPath animated:YES]; // select the relevant row in the table (assuming the table is self.tableView)
[self performSegueWithIdentifier:#"personProfile" sender:self]; // perform the segue
}
f) Note in the above that you should not call tableView:didSelectRowAtIndexPath:. This is for the tableView to call when the user selects the row, not for selecting rows programmatically. Use selectRowAtIndexPath:animated: instead.

This is basically pbasdf answer above with Swift 3
I do call didSelectRowAt directly since it is not triggered by selectRowAtIndexPath
The tag is set on cell creation with the row of the indexpath
The getTableView function is my own
#IBAction func actionButtonPushed(_ sender: Any) {
guard let button = sender as? UIButton else { return }
guard let tableView = getTableView() else { return }
let indexPath = IndexPath(row: button.tag, section: 0)
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
if let delegate = tableView.delegate {
delegate.tableView!(tableView, didSelectRowAt: indexPath)
}
}

Related

How to get the cell selection row in our own declaration method?

I have button in UITableView if user select the button then it have to go NextViewController [with carry of some JSON values].
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
orderid=[NSString stringWithFormat:#"%#",[[arrDictionary objectAtIndex:indexPath.row]objectForKey:#"orderid"]];
NSLog(#"orderid==%#",orderid);
}
I can easily get the values from the selected cell
I have button in UITableViewCell so i need to get the button click is from which row?
I tried with this code but its only display first orderid i have stored
-(void)nextview:(UIButton *)button
{
NSIndexPath *index=[tableview indexPathsForSelectedRows];
orderid=[NSString stringWithFormat:#"%#",[[arrDictionary objectAtIndex:index]objectForKey:#"orderid"]];
NSLog(#"orderid==%#",orderid);
}
If you have not working with multiple selection then you can get one row which is selected by :
NSIndexPath *index = [tableview indexPathForSelectedRow];
If you have multi row selection then :
You will get the array of selected NSIndexPath of selected index as like :
NSArray *selectedIndexPaths = [tableview indexPathsForSelectedRows];
You can run loop up to the selectedIndexPaths.count and get selected rows data.
DOCUMENT :
// Selection
- (NSIndexPath *)indexPathForSelectedRow;
// returns nil or index path representing section and row of selection.
- (NSArray *)indexPathsForSelectedRows NS_AVAILABLE_IOS(5_0);
// returns nil or a set of index paths representing the sections and rows of the selection.
you can get selected cell as
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[self.tableView indexPathForSelectedRow]];
and indexPath as [self.tableView indexPathForSelectedRow]
and I think you'll then pefror a segue
[self perfromSegueWithIdentifier:#"Segue"];
For Push json to NextViewController
-(void)YouButtonSelector:(UIButton *)sender{
NextViewController *rightController=[[NextViewController alloc] init];
rightController.eventIdIs=self.event_id;
rightController.PreviousJson=PresentJson;
rightController.hidesBottomBarWhenPushed=YES;
[self.navigationController pushViewController:rightController animated:YES];
}
For Button Clicked
[cell.checkboxBtn setTag:indexPath.row];
[cell.checkboxBtn addTarget:self action:#selector(nextview:) forControlEvents:UIControlEventTouchUpInside];
-(void)nextview:(UIButton *)button
{
NSLog(#"Button select is :%d",button.tag);
}
1 - You can give button tag in cellForRowAtIndexPath method
button.tag = indexPath.row;
2 - you have receive you orderid
-(void)nextview:(UIButton *)button
{
NSString *orderid=[NSString stringWithFormat:#"%#",[[arrDictionary objectAtIndex:button.tag] objectForKey:#"orderid"]];
NSLog(#"orderid==%#",orderid);
}
Assign
cell.btn.tag = indexPath.row;
and on button press function get data from array using
UIButton *btn = (UIButton *)sender;
NSString *str = arrDictionary[btn.tag];

UISwitch in CustomCell is not changing the value at specific indexpath

This is the type of screen I'm making:
So when the UISwitch state changes it should change the label to ON or OFF. In my cellForRowAtIndexPath I'm calling [cell.mainSwitch addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged]; and switchChanged is as follow:
-(void) switchChanged:(id)sender {
UISwitch* cellNew = (UISwitch*)sender;
if ([cellNew isOn]) {
cell.funcStatus.text = [funcStatusArr objectAtIndex:0];
} else {
cell.funcStatus.text = [funcStatusArr objectAtIndex:1];
}
}
Now the problem I'm facing is that it is not changing the Label at the specific cell butt all the switches are changing the Label of 4th(last) cell as shown in the figure below.
As you can see that the first label is off but it is changing the label of last row. Any ideas why it is happening or how to tell the functions that this index.row is sending the request.
So u must add tag property to all UISwitch. Fasters way its in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath call
// code
// its good work if u have only 1 section
mySwitch.tag = indexPath.row.
//code
Than fix u're code
-(void) switchChanged:(UISwitch*)switch {
SettingsTableViewCell *selectedCell;
NSIndexPath *selectedIndexPath;
if(switch.tag == 0)
// create selectedIndexPath with correctrly row and section
selectedIndexPath = [NSIndexPath indexPathForRow:'YourRow'inSection:'Your section']
// create cell
selectedCell = [self.tableView cellForIndexPath:selectedIndexPath];
} else if(switch.tag == 1) {
// same logic;
}
// and replace text for selected cell
if ([switch isOn]) {
selectedCell.funcStatus.text = [funcStatusArr objectAtIndex:0];
} else {
selectedCell.funcStatus.text = [funcStatusArr objectAtIndex:1];
}
}
it's must work.
You doing wrong thing.First you need to get cell at specific changed event.
follow this code.
-(void) switchChanged:(id)sender {
UISwitch* switchBtn = (UISwitch*)sender;
//self.tableView is UITableView's outlet named tableView
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
//First detect Tableview's Cell then do the stuff
//CustomCellTableViewCell replace it with you custom cell class
CustomCellTableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
if ([switchBtn isOn]) {
cell.funcStatus.text = [funcStatusArr objectAtIndex:0];
} else {
cell.funcStatus.text = [funcStatusArr objectAtIndex:1];
}
[self.tableView reloadRowsAtIndexPaths:[[NSArray alloc] initWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
}
Cheers.

How to get the indexPath of a UIButton in a UITableViewCell? [duplicate]

This question already has answers here:
How to know the UITableview row number
(10 answers)
Closed 5 years ago.
I have a UITableview with multiple cells. On each cell I'm adding buttons dynamically according to some array count. So, when I click on a button I'm able to get the tag value of the button. But how to get the indexPath of that cell?
Here is my code in -cellForRowAtIndexPath:
UIView *view=(UIView*)[cell.contentView viewWithTag:indexPath.row+444];
UIImageView *img=(UIImageView*)[cell.contentView viewWithTag:indexPath.row+999];
img.image=[UIImage imageNamed:#"BHCS_empty.png"];
if(integer!=50)
{
NSInteger y_axis=0;
NSArray *Arr=[tableSubCategoryArr objectAtIndex:indexPath.row];
img.image=[UIImage imageNamed:#"BHCS_selected.png"];
view.Frame= CGRectMake(0,50,281, integer-50);
for (int i=0; i<[Arr count]; i++)
{
NSLog(#"arr %#",[Arr objectAtIndex:i]);
UIButton *Btn=[UIButton buttonWithType: UIButtonTypeCustom];
Btn.frame=CGRectMake(0, y_axis, 281, 44);
[Btn setImage:[UIImage imageNamed:#"BHCS_panel.png"] forState:UIControlStateNormal];
[Btn addTarget:self action:#selector(subCategoryBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
[Btn setTag:i+100];
[view addSubview:Btn];
UILabel *nameLbl=[[UILabel alloc]initWithFrame:CGRectMake(20, y_axis,248, 44)];
nameLbl.text = [[Arr objectAtIndex:i]objectForKey:#"SubCategoryName"];
nameLbl.textColor = [UIColor whiteColor];
nameLbl.backgroundColor=[UIColor clearColor];
panelTableView.separatorColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"BHCS_panel_div1.png"]];
nameLbl.font = [UIFont fontWithName:#"Helvetica" size:12.0f];
[view addSubview:nameLbl];
y_axis=y_axis+44+1.3f;
}
}
I have tried maximum of given answers, but at the and I generally use to go for most Generalised and ideal way as follows:
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
ALLLLL of the answers here are bad and you shouldn't be looping through superviews. Classic example, with iOS 7 Apple changed the tableViewCell hierarchy and your app will now crash!
Use this instead:
How to know the UITableview row number
Updated answer
Use it like:
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
Thanks to all i slove this by using below code
NSIndexPath *indexPath = [panelTableView indexPathForCell:(UITableViewCell *)sender.superview.superview];
NSLog(#"%d",indexPath.row);
None of these answers seem like a very clean solution. The way I would implement this is by using the delegate pattern. The view controller is the cell's delegate, meaning you let the cell itself handle the button press, and it tells its delegate when the button was pressed so it can handle it however it wants.
Let's say you have a tableview where each cell represents a Person object, and when the button is pressed you want to show a profile for this person. All you need to do is this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PersonCell *cell = [tableView dequeueReusableCellWithIdentifier:#"customTableViewCell" forIndexPath:indexPath];
cell.delegate = self;
cell.person = self.people[indexPath.row];
return cell;
}
- (void)personCell:(PersonCell *)personCell didPressButtonForPerson:(Person *)person {
[self showProfileForPerson:person];
}
Then all you need to do in your button class is add a property called buttonPressedHandler that is a block passing back an instance of Person, and when you create your button and add the target do something like this:
- (void)viewDidLoad {
[super viewDidLoad];
// do whatever whatever else you need/want to here
[self.button addTarget:self selector:#selector(handleButtonPressed) forState:UIControlStateNormal];
}
- (void)handleButtonPressed {
// Make sure this is a required delegate method, or you check that your delegate responds to this selector first...
[self.delegate personCell:self didPressButtonForPerson:self.person];
}
Put this code in the button's action method:
NSIndexPath *indexPath = [yourtableviewname indexPathForCell:(UITableViewCell *)sender.superview];
NSLog(#"%d",indexPath.row);
I suggest adding a property to your custom UITableViewCell implementation class to store the indexPath. Then, when your cellForRowAtIndexPath delegate fires in your TableViewController, set the indexPath property for that cell.
customTableViewCell.h :
#interface customTableViewCell : UITableViewCell
#property NSIndexPath *indexPath;
#end
customTableViewController configure cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
customTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"customTableViewCell" forIndexPath:indexPath];
// Do whatever you want with your cell
cell.indexPath = indexPath;
return cell;
}
Then you can refer to the indexPath property in your customTableViewCell by calling self.indexPath
You can use UITableView's indexPathForCell: method like so [tableView indexPathForCell:cell];. Good Luck!

Best practice: handling actions from buttons inside tableview cells?

I have a "contact list" table view with "contact" cells that contain an email button that, when tapped, should present an email composer with the email address of that contact.
What is the best way to associate the UIButton with the "contact" instance of that cell?
I’ve created answers for the two approaches that come to mind – but which I don’t really find satisfactory. Which do you prefer, or much better still, suggest better ones!
Approach 2:
Make the cells handle the action and call a custom delegate method.
// YMContactCell.h
#protocol YMContactCellDelegate
- (void)contactCellEmailWasTapped:(YMContactCell*)cell;
#end
#interface YMContactCell
#property (weak, nonatomic) id<YMContactCellDelegate> delegate;
#end
// YMContactCell.m
- (IBAction)emailContact:(id)sender {
[self.delegate contactCellEmailWasTapped:self];
}
// ContactListViewController.m
- (void)contactCellEmailWasTapped:(YMContactCell*)cell;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
YMContact *contact = [[self fetchedResultsController] objectAtIndexPath:indexPath];
// present composer with `contact` ...
}
Doesn’t handling events in a view violate the MVC principle?
The way I most often see it done is by assigning tags to the buttons that are equal to the indexPath.row.
- (CustomCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.theLabel.text = self.theData[indexPath.row];
cell.button.tag = indexPath.row;
[cell.button addTarget:self action:#selector(doSomething:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
-(void)doSomething:(UIButton *) sender {
NSLog(#"%#",self.theData[sender.tag]);
//sender.tag will be equal to indexPath.row
}
Another solution:
For me something like this works flawlessly, and looks very elegant:
- (void)buttonClicked:(id)sender
CGPoint buttonPosition = [sender convertPoint:CGPointZero
toView:self.tableView];
NSIndexPath *clickedIP = [self.tableView indexPathForRowAtPoint:buttonPosition];
// When necessary
// UITableViewCell *clickedCell = [self.tableView cellForRowAtIndexPath:clickedIP];
}
Update 12/01/2017
After some time, and implementing lots of UITableViews, I need to admit that the best solution is using the delegation pattern, already suggested by others here.
Reading these answers, i would like say my opinion:
Cell by button position
- (void)buttonClicked:(id)sender
CGPoint buttonPosition = [sender convertPoint:CGPointZero
toView:self.tableView];
NSIndexPath *clickedIP = [self.tableView indexPathForRowAtPoint:buttonPosition];
// When necessary
// UITableViewCell *clickedCell = [self.tableView cellForRowAtIndexPath:clickedIP];
}
the solution above is certainly the most rapid to implement, but it is not the best from the point of view of the design/architecture. Moreover you obtain the indexPath but need to calculate any other info. This is a cool method, but would say not the best.
Cell by while cycle on the button superviews
// ContactListViewController.m
- (IBAction)emailContact:(id)sender {
YMContact *contact = [self contactFromContactButton:sender];
// present composer with `contact`...
}
- (YMContact *)contactFromContactButton:(UIView *)contactButton {
UIView *aSuperview = [contactButton superview];
while (![aSuperview isKindOfClass:[UITableViewCell class]]) {
aSuperview = [aSuperview superview];
}
YMContactCell *cell = (id) aSuperview;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
return [[self fetchedResultsController] objectAtIndexPath:indexPath];
}
Get the cell in this way is more expensive of the previous and it is not elegant as well.
Cell by button tag
- (CustomCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.theLabel.text = self.theData[indexPath.row];
cell.button.tag = indexPath.row;
[cell.button addTarget:self action:#selector(doSomething:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
-(void)doSomething:(UIButton *) sender {
NSLog(#"%#",self.theData[sender.tag]);
//sender.tag will be equal to indexPath.row
}
Absolutely no. Use the tag can seems a cool solution, but the tag of a control can be used for a lot of things, like the next responder etc. I don't like and this is not the right way.
Cell by design pattern
// YMContactCell.h
#protocol YMContactCellDelegate
- (void)contactCellEmailWasTapped:(YMContactCell*)cell;
#end
#interface YMContactCell
#property (weak, nonatomic) id<YMContactCellDelegate> delegate;
#end
// YMContactCell.m
- (IBAction)emailContact:(id)sender {
[self.delegate contactCellEmailWasTapped:self];
}
// ContactListViewController.m
- (void)contactCellEmailWasTapped:(YMContactCell*)cell;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
YMContact *contact = [[self fetchedResultsController] objectAtIndexPath:indexPath];
// present composer with `contact` ...
}
This is the solution. Use delegation or use blocks is really a nice thing to do because you can pass all parameters that you want and make the architecture scalable. In fact in the delegate method (but also with blocks) you could want send directly informations without having the need to calculate them later, like the previous solutions.
Enjoy ;)
Swift Closure Approach
I guess I found a new approach which is a bit swifty. Tell me what you think about it.
Your Cell:
class ButtonCell: UITableViewCell {
var buttonAction: ( () -> Void)?
func buttonPressed() {
self.buttonAction?()
}
}
Your UITableViewDataSource:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CallCell", for: indexPath)
//Handled inside
cell.buttonAction = {
//Button pressed
}
//Handle in method
cell.buttonAction = self.handleInnerCellButtonPress()
}
You can also pass data inside this call. Like the cell or something stored inside the cell.
Regards,
Alex
Approach 1:
Determine the cell, and thence the index path, by traversing the cell’s view hierarchy from the button.
// ContactListViewController.m
- (IBAction)emailContact:(id)sender {
YMContact *contact = [self contactFromContactButton:sender];
// present composer with `contact`...
}
- (YMContact *)contactFromContactButton:(UIView *)contactButton {
UIView *aSuperview = [contactButton superview];
while (![aSuperview isKindOfClass:[UITableViewCell class]]) {
aSuperview = [aSuperview superview];
}
YMContactCell *cell = (id) aSuperview;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
return [[self fetchedResultsController] objectAtIndexPath:indexPath];
}
It feels clunky to me. Kinda "meh"…
I would provide another approach, just doesn't assign the active target, the event will traverse upon the responder chain:
[self.actionButton addTarget:nil action:#selector(onActionButtonClick:) forControlEvents:UIControlEventTouchUpInside];
and then, in your view controller:
- (void)onActorButtonClick:(id)sender {
if ([sender isKindOfClass:UIButton.class]) {
UITableViewCell *cell = [self findAncestorTableCell:(UIView *)sender]; //See other answer to fetch the cell instance.
NSIndexPath *indexPath = [self.listTable indexPathForCell:cell];
...
}
}
However, this begets some compiler warning, add this to ignore them:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
...
#pragma clang diagnostic pop

How to make a button on a table view cell call the correct tableView:cellForRowAtIndexPath?

I have a button that is part of a custom UITableViewCell. What I want is that when someone clicks the button, that the proper tableView:cellForRowAtIndexPath to be called for that cell.
How do I tie the button to the proper cellForRowAtIndexPath?
Any suggestions and / or code samples will be highly appreciated
You can get the indexPath from the touch event. Modify your buttonTapped method to be this:
- (void) buttonTapped:(id) sender forEvent:(UIEvent *)event
and then use something like the following:
NSIndexPath *indexPath = [tableView indexPathForRowAtPoint:[[[event touchesForView:sender] anyObject] locationInView:tableView]];
If you have only one section, you can probably use UIView's tag property.
Something like follows would theoretically work.
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)idxPath
{
Your_UITableViewCell_Subclass * cell = [tableView dequeueCellWithIdentifier:#"..."];
cell.button.tag = idxPath.row;
....
return cell;
}
....
- (void) buttonTapped:(id) sender
{
int idx = ((UIButton *)sender).tag;
NSIndexPath * idxPath = [NSIndexPath indexPathForRow:idx inSection:0];
UITableViewCell * cell = [self tableView:tableView cellForRowAtIndexPath:idxPath];
// Do whatever you want to do with the cell
}

Resources