4

I am trying to make this work but can't seem to wrap my mind around the idea.

So far I have it to where you are able to select a cell and it be able to produce a checkmark. Then, when you select a different cell, the previous checkmark would go away and the tableview would make a new checkmark on the new cell you just selected. This all works beautifully.

However, I am wanting to make it to where when you select the same cell with the checkmark, the checkmark does not disappear. But, it does!

I have tried numerous amounts of if statements to see if I can figure out how to make this work but can't figure out a solution. It is probably something minor that I need to rearrange in my code.

Here is my code:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    if(self.checkedIndexPath)
    {
        UITableViewCell* uncheckCell = [tableView
                                        cellForRowAtIndexPath:self.checkedIndexPath];
        uncheckCell.accessoryType = UITableViewCellAccessoryNone;
        [tableView deselectRowAtIndexPath:indexPath animated:YES];

    }

    if([self.checkedIndexPath isEqual:indexPath])
    {
        self.checkedIndexPath = nil;
    }

    else
    {
         cellCheck = [tableView cellForRowAtIndexPath:indexPath];
        cellCheck.accessoryType = UITableViewCellAccessoryCheckmark;
        self.checkedIndexPath = indexPath;
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        NSLog(@"%@", indexPath);

    }
}
Zack
  • 871
  • 10
  • 24

2 Answers2

12

If you select the cell with checkmark, this code will be executed.

if(self.checkedIndexPath)
{
    UITableViewCell* uncheckCell = [tableView
                                     cellForRowAtIndexPath:self.checkedIndexPath];
     uncheckCell.accessoryType = UITableViewCellAccessoryNone;
     [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

This code will remove the checkmark which you have added during the first select.

then this code will be executed

if([self.checkedIndexPath isEqual:indexPath])
{
    self.checkedIndexPath = nil;
}

Thus only when you select the same cell again, the checkmark will reappear

I think the cleaner way will be as followed.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell* cellCheck = [tableView
                                    cellForRowAtIndexPath:indexPath];
    cellCheck.accessoryType = UITableViewCellAccessoryCheckmark;
}

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell* uncheckCell = [tableView
                                    cellForRowAtIndexPath:indexPath];
    uncheckCell.accessoryType = UITableViewCellAccessoryNone;
 }

AS you can get the value for self.checkedIndexPath from [tableView indexPathForSelectedRow]; the setting of self.checkedIndexPath is optional depending on the logic of your code.

0

You don't manipulate the cells directly like that, store the checked state somewhere and change the accessoryType in cellForRowAtIndex:

static BOOL checkedRows[100]; // example data storage

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{
    checkedRows[indexPath.row] = !checkedRows[indexPath.row];
    [tableView reloadData];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{

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

    if(!cell)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }

    cell.accessoryType = checkedRows[indexPath.row] ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;

    return cell;
}
oskob
  • 1,386
  • 1
  • 11
  • 27
  • 1
    Actually, changing the `accessoryType` as the OP shows is perfectly fine. This is a common way to uncheck the current row and check the new row without the need to tell the table view to reload the two rows. Reloading the entire table to change the `accessoryType` of two rows is overkill and very inefficient. Also, since he only wants one row selected at any given, there is no reason to use an array to track the selected row. A single value is enough. – rmaddy Nov 04 '12 at 00:24
  • But since TableViewCells are reused when scrolling, when you scroll down a bit that UITableViewCell object will be used for another row, resetting the accessoryType to what ever is the standard value in cellForRowAtIndex. If you dont reset it, the checkmark will appear for some other arbitrary row when reused, won't it? – oskob Nov 04 '12 at 09:39
  • But since you also update your data model, as you scroll the cells will be properly updated as `tableView:cellForRowAtIndexPath:` is called. In the end, you always adjust the accessoryType in `cellForRow...`, and in `didSelectRow...` you either adjust the accessoryType or you reload just the affects row(s). – rmaddy Nov 04 '12 at 15:27