Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I retrieve UITableView row number of a UISwitch?

I have tried several approaches posted here, but I cannot get my table full of switches to return an index value for the cell of the changed switch. I am creating the view containing the table programmatically (no xib).

TableSandboxAppDelegate.m I instantiate the view controller in didFinishLaunchingWithOptions: with:

...
TableSandboxViewController *sandboxViewController = [[TableSandboxViewController alloc]
    init];
[[self window] setRootViewController:sandboxViewController];
...

TableViewController.h file reads:

@interface TableSandboxViewController : UITableViewController
{
   NSMutableArray *_questionOrder;
   NSMutableArray *switchStates;
}
@end

TableViewController.m cellForRowAtIndexPath: reads:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MainCell"];

UISwitch *theSwitch = nil;

if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
        reuseIdentifier:@"MainCell"];

    theSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
    theSwitch.tag = 100;
    [theSwitch addTarget:self action:@selector(switchChanged:)   
        forControlEvents:UIControlEventValueChanged];
    [cell.contentView addSubview:theSwitch];

} else {
    theSwitch = [cell.contentView viewWithTag:100];
}

if ([[switchStates objectAtIndex:indexPath.row] isEqualToString:@"ON"]) {
    theSwitch.on = YES;
} else {
    theSwitch.on = NO;
}

return cell;

TableViewController.m -(IBAction)switchChanged:(UISwitch *)sender reads:

UITableViewCell *theParentCell = [[sender superview] superview];
NSIndexPath *indexPathOfSwitch = [self.tableView indexPathForCell:theParentCell];

NSLog(@"Switch changed at index: %d", indexPathOfSwitch.row);

My log result is always "Switch changed at index: 0". I feel like the problem is in that CGPoint line where I've tried combinations of replacements for "sender" ([sender superview], [[sender superview]superview], etc). I don't feel like that line is pointing to the view that displays the table.

What am I doing wrong?

Note added 10/9, 9:15 EDT: my goal is to be able to handle about 100 yes/no questions in the table, so reuse is a key. I want to scroll and have the table the state of each switch, as well as be able to retrieve them when leaving the view.

like image 907
dmccall Avatar asked Oct 09 '13 03:10

dmccall


People also ask

How do you get the indexPath row when a button in a cell is tapped?

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.

What does indexPath row return?

So to start with the indexPath. row will be 0. Then it will be 1, then 2, then 3 and so on. You do this so that you can get the correct string from the array each time.


2 Answers

Tags is an okay solution, but a little clumsy because the cells - and therefore their subviews - are continually being reused, changing their rows - and therefore the tags they need.

Instead, I generally keep one of these around:

- (NSIndexPath *)indexPathWithSubview:(UIView *)subview {

    while (![subview isKindOfClass:[UITableViewCell self]] && subview) {
        subview = subview.superview;
    }
    return [self.tableView indexPathForCell:(UITableViewCell *)subview];
}

Then when I get an IBAction:

- (IBAction)someSubviewAction:(id)sender {

    NSIndexPath *indexPath = [self indexPathWithSubview:(UIView *)sender];
    // carry on from here
}
like image 149
danh Avatar answered Sep 28 '22 05:09

danh


You may set switch view tag to row index. Instead of theSwitch.tag = 100;

do

-(UITableViewCell*)tableView:table cellForRowAtIndexPath:indexPth
{
    UISwitch *theSwitch = nil;
    if (cell == nil) {
        ...
        // as per your example
        [cell.contentView addSubview:theSwitch];
    } else {
        theSwitch = subviewWithClass(cell.contentView, [UISwitch class]);
    }

    theSwitch.tag = indexPath.row;
    ...
}

Add this helper function to replace viewWithTag: call

UIView *subviewWithClass(UIView *contentview, Class klass)
{
    for (UIView *view in contentview.subviews)
        if ([view isKindOfClass:klass])
            return view;
    return nil;
}

Then retrieve tag, that is a row index now, in your switchChanged function

-(IBAction)switchChanged:(UISwitch *)sender {
    NSLog(@"Selected Switch - %d", sender.tag);
    ...
 }
like image 24
dmitri Avatar answered Sep 28 '22 04:09

dmitri