Gogo Gogo - 2 months ago 20
iOS Question

Check markers in UITableView are not accurate

I'm trying to learn UITableViews.

When I press a row a check marker shows up, but when I scroll other rows are selected too, and some rows don't show a check marker on the first tap, but they do when I tap it twice. Why are they so inaccurate?

Any help appreciated!

CODE:

@interface AnimalTableTableViewController () {
NSDictionary *animals;
NSArray *animalSectionTitles;
NSArray *animalIndexTitles;
}

@end

@implementation AnimalTableTableViewController

- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}

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

NSUInteger row = indexPath.row;
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];

if ([self.selectedRows containsIndex:row]) {

[self.selectedRows removeIndex:row];
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];

} else {

[self.selectedRows addIndex:indexPath.row];
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];

}

[tableView deselectRowAtIndexPath:indexPath animated:YES];

}

- (IBAction)generateRecipeAction:(id)sender {

if ([self.selectedRows containsIndex:0] && [self.selectedRows containsIndex:1]) {

NSLog(@"Row 1 and 2 selected.");

}

}

- (void)viewDidLoad

{

[super viewDidLoad];

self.selectedRows = [NSMutableIndexSet new];

// animals = @[@"Bear", @"Black Swan", @"Buffalo", @"Camel", @"Cockatoo", @"Dog", @"Donkey", @"Emu", @"Giraffe", @"Greater Rhea", @"Hippopotamus", @"Horse", @"Koala", @"Lion", @"Llama", @"Manatus", @"Meerkat", @"Panda", @"Peacock", @"Pig", @"Platypus", @"Polar Bear", @"Rhinoceros", @"Seagull", @"Tasmania Devil", @"Whale", @"Whale Shark", @"Wombat"];

animals = @{@"B" : @[@"Bear", @"Black Swan", @"Buffalo"],
@"C" : @[@"Camel", @"Cockatoo"],
@"D" : @[@"Dog", @"Donkey"],
@"E" : @[@"Emu"],
@"G" : @[@"Giraffe", @"Greater Rhea"],
@"H" : @[@"Hippopotamus", @"Horse"],
@"K" : @[@"Koala"],
@"L" : @[@"Lion", @"Llama"],
@"M" : @[@"Manatus", @"Meerkat"],
@"P" : @[@"Panda", @"Peacock", @"Pig", @"Platypus", @"Polar Bear"],
@"R" : @[@"Rhinoceros"],
@"S" : @[@"Seagull"],
@"T" : @[@"Tasmania Devil"],
@"W" : @[@"Whale", @"Whale Shark", @"Wombat"]};

animalSectionTitles = [[animals allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
animalIndexTitles = @[@"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z"];
}

- (NSString *)getImageFilename:(NSString *)animal
{
NSString *imageFilename = [[animal lowercaseString] stringByReplacingOccurrencesOfString:@" " withString:@"_"];
imageFilename = [imageFilename stringByAppendingString:@".jpg"];

return imageFilename;
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [animalSectionTitles count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSString *sectionTitle = [animalSectionTitles objectAtIndex:section];
NSArray *sectionAnimals = [animals objectForKey:sectionTitle];
return [sectionAnimals count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [animalSectionTitles objectAtIndex:section];
}

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

// Configure the cell...
NSString *sectionTitle = [animalSectionTitles objectAtIndex:indexPath.section];
NSArray *sectionAnimals = [animals objectForKey:sectionTitle];
NSString *animal = [sectionAnimals objectAtIndex:indexPath.row];
cell.textLabel.text = animal;
cell.imageView.image = [UIImage imageNamed:[self getImageFilename:animal]];

return cell;
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
// return animalSectionTitles;
return animalIndexTitles;
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return [animalSectionTitles indexOfObject:title];
}

@end

Answer

You need to make sure you set the cell accessory correctly in cellForRowAtIndexPath. Since cells are re-used you need to explicitly set or clear the accessory.

Also, since you have multiple sections, and row numbers start at 0 within each section, you will need multiple NSMutableIndexSets; one for each section. I would suggest you use a dictionary to hold these:

@property (strong,nonatomic) NSMutableDictionary *selectionSets;

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

    NSUInteger row = indexPath.row;
    NSMutableIndexSet *selectionSet = self.selectionSets[animalSectionTitles[indexPath.section]];
    if (selectionSet == nil) {
        selectionSet = [NSMutableIndexSet new];
        self.selectionSets[animalSectionTitles[indexPath.section]] = selectionSet;
    }

    UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];

    if ([selectionSet containsIndex:row]) {
        [selectionSet removeIndex:row];
        [selectedCell setAccessoryType:UITableViewCellAccessoryNone];
    } else {
        [selectionSet addIndex:indexPath.row];
        [selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
    }
}


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

// Configure the cell...
    NSString *sectionTitle = [animalSectionTitles objectAtIndex:indexPath.section];
    NSMutableIndexSet *selectionSet = self.selectionSets[sectionTitle];
    NSArray *sectionAnimals = [animals objectForKey:sectionTitle];
    NSString *animal = [sectionAnimals objectAtIndex:indexPath.row];
    cell.textLabel.text = animal;
    cell.imageView.image = [UIImage imageNamed:[self getImageFilename:animal]];

    NSUInteger row = indexPath.row;

    if ([selectionSet containsIndex:row]) {
        [cell setAccessoryType:UITableViewCellAccessoryCheckmark];       
    } else {
        [cell setAccessoryType:UITableViewCellAccessoryNone];
    }

    return cell;
}