Question

I have an UISwitch in my UITableViewCell prototype.

The problem is, when I turn on one of the switches, one of the not shown switches also gets turned on.

This doesn't happen in the iPad version where all cells are shown.

Here is some code:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *identifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

    Notification *notification = [notifications objectAtIndex:indexPath.row];

    UILabel *titleLabel = (UILabel *) [cell viewWithTag:100];
    UISwitch *newsSwitch = (UISwitch *) [cell viewWithTag:101];
    UIImageView *imageView = (UIImageView *) [cell viewWithTag:102];

    [titleLabel setText:[notification name]];
    [imageView setImage:[UIImage imageNamed:[notification image]]];

    BOOL isOn = [storage boolForKey:[NSString stringWithFormat:@"notification_%@", [notification name]]];
    [newsSwitch setOn:isOn];
    [newsSwitch setTag:indexPath.row];
    [newsSwitch addTarget:self action:@selector(didChangeStateForSwitch:) forControlEvents:UIControlEventValueChanged];

    return cell;
}
Was it helpful?

Solution

Your problem is that you first query the switch via its tag:

UISwitch *newsSwitch = (UISwitch *) [cell viewWithTag:101];

But later on, you change that tag:

[newsSwitch setTag:indexPath.row];

So when the cell gets reused, the switch won't be found as now its tag isn't 101 any more. Therefor, the switch will be stuck in its old state.

You can easily verify this by adding a NSLog(@"Switch: %@", newsSwitch); after querying the switch. You'll see that it'll output Switch: (null) for those rows where you have "wrong" switch values.

The solution this is to not modify the tag.

Question is, how do you remember which row the switch is for, then? One way would be this:

- (void)didChangeStateForSwitch:(id)sender
{
    NSIndexPath *indexPath = [myTableView indexPathForCell:[sender superview]];
    ...
}

Another possibility is to use associated objects.

OTHER TIPS

First time when you load the cell you are taking the view with tag 101 for switch.Few lines after that you are setting new tag to this switch and next time when you try to take the view with tag 101 it doesn't exist.[newsSwitch setTag:indexPath.row]; delete this line and try again

You can get the index path as @DarkDust suggested

- (void)didChangeStateForSwitch:(id)sender
{
NSIndexPath *indexPath = [myTableView indexPathForCell:[sender superview]];
...
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top