This is a little harder than it sounds.

UITableView reuses cells – so you can’t just detect with row was selected and then expect that cell to be selected later. That cell will be recycled and your index will be lost.

So what we do is create a separate data structure (say a mutable array) to track which rows were selected, and then turn rows on and off by toggling a check mark.

The data structure

In my app I need to track which photos are selected:

So I am going to create an NSMutableArray to do that:

ViewController.h

@property (nonatomic, strong) NSMutableArray *selectedPhotoTracker;

ViewController.m

@synthesize selectedPhotoTracker = _selectedPhotoTracker;

and I am going to initialize him once my photos have loaded:

ViewController.m

-(void) initializeSelectedPhotoTracker {
    NSLog(@"initializeSelectedPhotoTracker");
    NSMutableArray *tracker = [NSMutableArray array];
    for (int i = 0; i < [[self photos] count] ; i++) {
        [tracker addObject:[NSNumber numberWithBool:NO]];
    }
    
    self.selectedPhotoTracker = tracker;    
}


-(void) refresh {
    
    NSLog(@"refresh");
    
    NSMutableArray *collector = [[NSMutableArray alloc] initWithCapacity:0];
    ALAssetsLibrary *al = [Utils defaultAssetsLibrary];
    
    [al enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
                      usingBlock:^(ALAssetsGroup *group, BOOL *stop) 
     {
         
         [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
          {
              if (asset) {
                  
                  // check for tag
                  NSDictionary *metadata = asset.defaultRepresentation.metadata;
                  NSDictionary *tiffDictionary = [metadata objectForKey:(NSString *)kCGImagePropertyTIFFDictionary];
                  NSString *takeMyStuffValue = [tiffDictionary objectForKey:(NSString *)kCGImagePropertyTIFFMake];

                  if ([takeMyStuffValue isEqualToString:TAKEMYSTUFF_METATAG]) {
                      [collector addObject:asset];
                  }
                  
              }  
          }];
         
         self.photos = collector;
         [self initializeSelectedPhotoTracker];
     }
                    failureBlock:^(NSError *error) { NSLog(@"Error refreshing photos.");}
     ];
}

Note: this looks more complicated that it really is but I included it to make that point that when you initialize this array matters.

First time I did this I tried putting :

         [self initializeSelectedPhotoTracker];

in the viewWillAppear view lifecycle method. It didn’t work because the photos (which are loaded in a separate thread in another block) hadn’t finished yet.

So if you are loading your data structure and nothing is there look out for that. Where you do your load and initialization matters.

Multi-row selection

This part is pretty straight forward. Apple doesn’t actually like you using blue highlighted row as an indicator of whether a row is selected (human interface guidelines).

They prefer you use check marks.

So with our datastructure in place we can just turn checkmarks on and off like this:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    int selectedRow = indexPath.row;

    NSDictionary *selectedPhoto = [[self selectedPhotoTracker] objectAtIndex:selectedRow];
    NSString *urlKey = [[selectedPhoto allKeys] objectAtIndex:0];
    
    // add checkmark
    UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
    
    if (thisCell.accessoryType == UITableViewCellAccessoryNone) {
        thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
        [selectedPhoto setValue:[NSNumber numberWithBool:YES] forKey:urlKey];        
    } 
    else 
    {
        thisCell.accessoryType = UITableViewCellAccessoryNone;
        [selectedPhoto setValue:[NSNumber numberWithBool:NO] forKey:urlKey];        
    }

    [[self selectedPhotoTracker] replaceObjectAtIndex:selectedRow withObject:selectedPhoto];
    [[self getSelectedImages] writeToDocumentDirectory:SELECTED_PHOTOS_FILE];
}

This method tracks that a row was selected and updates our model, and then it toggles the checkmark on or off respectively.

Links that help:
http://stackoverflow.com/questions/308081/is-it-possible-to-configure-a-uitableview-to-allow-multiple-selection

http://stackoverflow.com/questions/5370311/uitableview-didselectrowatindexpath-add-additional-checkmark-at-tap