user969043
user969043

Reputation: 766

iOS: Tableview multiple selection - AccessoryCheckmark checking reusable cells

I'm using a tableview with sections and multiple selection, but I have an issue with multiple rows being checked when one row is chosen... I've seen a few other threads about this, but didn't really get a solution...

Here's my code:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *) indexPath
{    
    [employeeTable deselectRowAtIndexPath:[employeeTable indexPathForSelectedRow] animated:NO];

    UITableViewCell *cell = [employeeTable cellForRowAtIndexPath:indexPath];    

    // get the letter in each section
    NSString *alphabet = [charIndex objectAtIndex:indexPath.section];

    // get the names beginning with the letter
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] %@", alphabet];    

    NSArray *names = [listOfNames filteredArrayUsingPredicate:predicate];    

    NSString *name = [names objectAtIndex:indexPath.row];

    for(int i = 0; i < [employeeConnection.employees count]; i++)
    {
        Employee *aEmployee = [employeeConnection.employees objectAtIndex:i];

        NSString *firstName = aEmployee.firstName;
        NSString *lastName = aEmployee.lastName;
        NSString *fullName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];

        if([fullName isEqualToString:name])
        { 
            NSLog(@"Name: %@", name);

            if (cell.accessoryType == UITableViewCellAccessoryNone) {

                cell.accessoryType = UITableViewCellAccessoryCheckmark;

                // Reflect selection in data model
                [chosenEmployees addObject:aEmployee.employeeID];
                [chosenEmployeesNames addObject:name];

            } else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {

                cell.accessoryType = UITableViewCellAccessoryNone;

                // Reflect deselection in data model
                [chosenEmployees removeObject:aEmployee.employeeID];
                [chosenEmployeesNames removeObject:name];
            }
        }
    }
}

Update: Added cellForRowAtIndexPath

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

        cell.textLabel.textColor = [UIColor whiteColor];
    }

    // Get the letter in the current section
    NSString *alphabet = [charIndex objectAtIndex:[indexPath section]];

    // Get the names beginning with the letter
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] %@", alphabet];
    NSArray *names = [listOfNames filteredArrayUsingPredicate:predicate];

    if([names count] > 0)
    {
        // Extract the name
        cell.textLabel.text = [names objectAtIndex:indexPath.row];
    }

    return cell;
}

Upvotes: 2

Views: 5298

Answers (2)

Christian Schnorr
Christian Schnorr

Reputation: 10786

I would suggest storing an NSMutableSet of either the checked ManagedObject (when using CoreData) or simply the checked IndexPaths. In -cellForRowAtIndexPath: you can then check if the cell is supposed to be checked.

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
        cell.textLabel.textColor = UIColor.whiteColor;
    }

    if ([self.checkedIndexPaths containsObject:indexPath]) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    }
    else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *const cell = [tableView cellForRowAtIndexPath:indexPath];
    [table deselectRowAtIndexPath:indexPath animated:NO];

    if ([self.checkedIndexPaths containsObject:indexPath]) {
        [self.checkedIndexPaths removeObject:indexPath];
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    else {
        [self.checkedIndexPaths addObject:indexPath];
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    }
}

Upvotes: 10

Lefteris
Lefteris

Reputation: 14687

Since cells are being reused, you need to set the accessory mark to on or off for every cell in the table in the cellForRowAtInexPath table datasource method.

So the cell.accessoryType cell property should be soecified in the cellForRowAtInexPath and not the didSelectRow delegate method.

In the didSelectRow, just keep track of the selected rows in an array, and set the cells accessory mark to none or checkmark in the cellForRowAtInexPath dependingon the array value.

Upvotes: 0

Related Questions