Getting the Next and the Previous NSIndexPath Instances

Very often, when you work with UITableViewControllers driven by NSFetchedResultsControllers, that you want to get the “previous” or the “next” elements in the results controller. Visually, this operation corresponds, from the point of view of the user, to select the cell that sits immediately above or below from the currently selected one.

Of course, you can’t just ++ on the current NSIndexPath, because these objects have both a section and a row component, and the math required to jump from one to the other can be quite cumbersome; instead, it would be useful to have a reusable set of methods, and avoid the clutter in our controllers.

I have created a very simple category on the NSFetchedResultsController class that retrieves the “next” and the “last” NSIndexPath given any other NSIndexPath; this can be dropped and reused in your projects and is very simple to use.

Interface

#import <CoreData/CoreData.h>
@interface NSFetchedResultsController (AKOLibrary)
- (NSIndexPath *)ako_incrementIndexPath:(NSIndexPath *)oldIndexPath;
- (NSIndexPath *)ako_decrementIndexPath:(NSIndexPath *)oldIndexPath;
@end

Implementation

#import "NSFetchedResultsController+AKOLibrary.h"
@implementation NSFetchedResultsController (AKOLibrary)
- (NSIndexPath *)ako_incrementIndexPath:(NSIndexPath *)oldIndexPath
{
    NSIndexPath *nextIndexPath = nil;
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self sections] objectAtIndex:oldIndexPath.section];
    NSInteger rowCount = [sectionInfo numberOfObjects];
    NSInteger nextRow = oldIndexPath.row + 1;
    NSInteger currentSection = oldIndexPath.section;
    if (nextRow < rowCount)
    {
        nextIndexPath = [NSIndexPath indexPathForRow:nextRow inSection:currentSection];
    }
    else
    {
        NSInteger sectionCount = [[self sections] count];
        NSInteger nextSection = currentSection + 1;
        if (nextSection < sectionCount)
        {
            nextIndexPath = [NSIndexPath indexPathForRow:0 inSection:nextSection];
        }
    }
    return nextIndexPath;
}
- (NSIndexPath *)ako_decrementIndexPath:(NSIndexPath *)oldIndexPath
{
    NSIndexPath *previousIndexPath = nil;
    NSInteger nextRow = oldIndexPath.row - 1;
    NSInteger currentSection = oldIndexPath.section;
    if (nextRow >= 0)
    {
        previousIndexPath = [NSIndexPath indexPathForRow:nextRow inSection:currentSection];
    }
    else
    {
        NSInteger nextSection = currentSection - 1;
        if (nextSection >= 0)
        {
            previousIndexPath = [NSIndexPath indexPathForRow:0 inSection:nextSection];
        }
    }
    return previousIndexPath;
}
@end

How to use

To use this class, just do the following:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:19 inSection:4];
NSIndexPath *next = [controller ako_incrementIndexPath:indexPath];
NSIndexPath *previous = [controller ako_decrementIndexPath:indexPath];

If the NSIndexPath (19,4) was the last of whole table, next would be nil. The same, if NSIndexPath was the first (0, 0), then previous would be nil. In all other situations, the next and previous index paths will correspond to the cells immediately above or below from the current table.

Hope this helps!

Similar Posts: