When i select a player in \'didSelectRowAtIndexPath\' and add a checkmark on the selected row it adds an additional checkmark.
If i tap row = 0 it adds a checkmark to ro
For others coming here (like I did) to see why their table selects random cells, you have to add something like the following to your cellForRowAtIndexPath:
// Assume cell not checked;
[cell setAccessoryType:UITableViewCellAccessoryNone];
for (int i = 0; i < checkedIndexPaths.count; i++) {
NSUInteger num = [[checkedIndexPaths objectAtIndex:i] row];
if (num == indexPath.row) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
}
I keep a NSMutableArray called checkedIndexPaths so that I know which indexPaths are checked. Keeping such an array allows you to easily limit the number of cells a user can check. Here's an example of my didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// uncheck if already checked
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
[checkedIndexPaths removeObject:indexPath];
}
else {
// make sure no more than 3 are selected
if ([checkedIndexPaths count] < 3) {
// check row
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// add it to our list of checked indexes
[checkedIndexPaths addObject:indexPath];
} else {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Note"
message:@"You can only select 3 rows."
delegate:nil
cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
}
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I am using storyboards with Dynamic Prototype Cells to display a list of states I used some of the ideas above before I found this solution
Step 1
@interface StateViewController : UITableViewController
{
NSMutableArray *checkedIndexPaths;
}
Step 2
(void)viewDidLoad
{
[super viewDidLoad];
self.states = [[GAIGStateStore sharedInstance]allStates];
//Setup default array to keep track of the checkmarks
checkedIndexPaths = [NSMutableArray arrayWithCapacity:self.states.count];
for (int i = 0; i < self.states.count; i++) {
[checkedIndexPaths addObject:[NSNumber numberWithBool:NO]];
}
}
Step 3
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//This toggles the checkmark
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
//This sets the array
[checkedIndexPaths replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:YES]];
} else
{
cell.accessoryType = UITableViewCellAccessoryNone;
//This sets the array
[checkedIndexPaths replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:NO]];
}
}
Step 4
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:stateCell forIndexPath:indexPath];
UILabel *stateLabel = (UILabel *)[cell viewWithTag:1000];
StateProvince *myState = [self.states objectAtIndex:indexPath.row];
stateLabel.text = myState.label;
//Now set the check marks
// Assume cell not checked;
[cell setAccessoryType:UITableViewCellAccessoryNone];
NSNumber *num = [checkedIndexPaths objectAtIndex:indexPath.row];
if (num == [NSNumber numberWithBool:YES]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
return cell;
}
The problem you are facing is caused by cell reusing.
Basically, if your UITableView has, let say 50 cells to display, it creates only 10 and then reuse them as you scroll down / scroll up. So whatever changes you did to the cell at row 0, it will be re-displayed for the row 11 as TableView uses the same cell etc.
What you want to do is to keep track of which players have been selected independently from cell. You can achieve that easily by creating a collection, let say NSMutableArray or NSMutableDictionary, which will store BOOL values in NSNumber objects, eg.
NSMutableArray *players = [NSMutableArray arrayWithCapacity:50];
for (int i = 0; i < 50; i++) {
[players addObject:[NSNumber numberWithBool:NO]];
}
Then in didSelectRowAtIndexPath:(NSIndexPath *)indexPath you do instead of operating on cell, you will simply change the value of a corresponding NSNumber object.
Then in cellForRowAtIndexPath:(NSIndexPath *)indexPath you configure cell accessory by checking the corresponding entry in players collection.
Or if you are really, really stubborn you could replace (THIS IS NOT RECOMENDED) the following line from the cellForRowAtIndexPath:(NSIndexPath *)indexPath:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
with:
UITableViewCell *cell = nil;