Question

I am using Apple's MultiSelectTableView as a way to learn about NSIndexSet. I can easily create selected items and read them back in the debugger.

I've tried several methods to "read" the set when the app runs again, but I can't figure this out. So, if I select a few rows and quit the app, the next time I run, the selections are not sustained. I've read this post, among others, but I'm just not grokking it.

I have been trying to use NSUserDefaults for this:

NSMutableIndexSet *indicesOfItemsToShow = [NSMutableIndexSet new];

for (NSIndexPath *selectionIndex in selectedRows)
{
    [indicesOfItemsToShow addIndex:selectionIndex.row];
    NSLog(@"selectionIndex.row: %i", selectionIndex.row);
    NSUserDefaults *standardDefaults;
    [standardDefaults setObject:selectionIndex forKey:@"currentState"];
    [standardDefaults synchronize];
}

When I log the debugger as the view loads, the index is null.

Was it helpful?

Solution

Index sets are not the correct tool to use for multiple-row selection in table views, because table view data is represented by sections and rows, while index sets contain one dimensional indexes.

If you wish to persist a multiple selection, you can use the -[UITableView indexPathsForSelectedRows] which returns an array of NSIndexPath objects. You can then persist this array, and on load, read it the array and use -[UITableView selectRowAtIndexPath:animated:scrollPosition:] to select the correct cells.

Also, you seem to be saving incorrectly to the user defaults.

NSUserDefaults *standardDefaults;
[standardDefaults setObject:selectionIndex forKey:@"currentState"];

Should be

NSUserDefaults *standardDefaults = [NSUserDefaults standardDefaults];
[standardDefaults setObject:selectionIndex forKey:@"currentState"];

A word of caution. Depending on how you populate data in your table view, this can be potentially unsafe to persist indexes of selected rows. It would be much better to keep track of which backing object are selected and use this information to select the rows. But for static data, this is OK.


To further explain how to persist the selection, here is an example:

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
    NSArray* selectedRows = [tableView indexPathsForSelectedRows];
    NSMutableArray* safeForUserDefaults = [NSMutableArray new];

    [selectedRows enumerateObjectsUsingBlock:^(NSIndexPath* indexPath, NSUInteger idx, BOOL *stop)
    {
        NSDictionary* data = @{@"section": @(indexPath.section), @"row": @(indexPath.row)};
        [safeForUserDefaults addObject:data];
    }];

    [[NSUserDefaults standardDefaults] setObject:safeForUserDefaults forKey:@"currentState"];
}

Now, to load:

- (void)viewDidLoad
{
    NSArray* previousState = [[NSUserDefaults standardDefaults] objectForKey:@"currentState"];

    [previousState enumerateObjectsUsingBlock:^(NSDictionary* data, NSUInteger idx, BOOL *stop)
    {
        [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:[data[@"row"] integerValue] inSection:[data[@"section"] integerValue]] animated:NO scrollPosition:UITableViewScrollPositionNone];
    }];
}

This is a very simplistic example, but should get you on your way.

OTHER TIPS

Just before you quit the app add self.storeIndexArray to NSUserDefaults

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

[self.storeIndexArray addObject:indexPath];

}

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

[self.storeIndexArray removeObject:indexPath];

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top