I have a UITableViewCell
with UISwitch
as accessoryview of each cell. When I change the value of the switch in a cell, how can I know in which row
i dont know about the multiple sections but i can give you for the one section...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger index=indexPath.row;
NSString *string=[[NSString alloc]initWithFormat:@"%ld",(long)index];
}
from this you can get the row number and you can save it to the string....
One common way to do this is to set the tag
of the control (in your case the switch) to something that can be used to identify the row or represented object.
For example, in tableView:cellForRowAtIndexPath:
set the tag
property of the switch to the indexPath.row
and in your action method you can get the tag from the sender.
Personally, I don't like this approach and prefer subclassing UITableViewCell. Also, it may be a good idea to add an "offset" to the tag to prevent any conflicts with the tags of other views.
If you set the tag
property to the row number (as suggested by other answers), you have to update it every time in tableView:cellForRowAtIndexPath:
(because a cell can be reused for different rows).
Instead, when you need the row number, you can walk up the superview
chain from the UISwitch
(or any other view) to the UITableViewCell
, and then to the UITableView
, and ask the table view for the index path of the cell:
static NSIndexPath *indexPathForView(UIView *view) {
while (view && ![view isKindOfClass:[UITableViewCell class]])
view = view.superview;
if (!view)
return nil;
UITableViewCell *cell = (UITableViewCell *)view;
while (view && ![view isKindOfClass:[UITableView class]])
view = view.superview;
if (!view)
return nil;
UITableView *tableView = (UITableView *)view;
return [tableView indexPathForCell:cell];
}
This doesn't require anything in tableView:cellForRowAtIndexPath:
.
The accepted answer on this post is perfectly fine. I'd like to suggest to readers that the following, derived from @robmayoff on this post, is also perfectly fine:
- (NSIndexPath *)indexPathForView:(UIView *)view inTableView:(UITableView *)tableView {
while (view && ![view isKindOfClass:[UITableViewCell class]])
view = view.superview;
UITableViewCell *cell = (UITableViewCell *)view;
return [tableView indexPathForCell:cell];
}
Some have asserted that this approach contains too much computational work because of the while loop. The alternative, convert the view's origin to table view coordinate space and call indexPathForRowAtPoint:
, hides even more work.
Some have asserted that this approach is unsafe relative to potential SDK changes. In fact, Apple has already changed the tableview cell hierarchy once, adding a contentView
to the cell. This approach works before and after such a change. As long as view ancestors can be found via a chain of superviews (which is as fundamental as anything in UIKit), this is good code.
One more variant of using superView. Works like category for UIView.
- (UITableViewCell *)superCell
{
if (!self.superview) {
return nil;
}
if ([self.superview isKindOfClass:[UITableViewCell class]]) {
return (UITableViewCell *)self.superview;
}
return [self.superview superCell];
}
I prefer using subviews, if you know your layout it's generally super simple and 1 line short...
NSIndexPath *indexPath = [tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];
Thats it, if its more nested, add in more superviews.
Bit more info:
all you are doing is asking for the parent view and its parent view which is the cell. Then you are asking your tableview for the indexpath of that cell you just got.