Core Data Table View Section Sort by weekdays using NSSortDescriptor

user255004 picture user255004 · Jan 30, 2010 · Viewed 7.2k times · Source

I'm currently trying to sort my array of objects into day order so they can be grouped in the correct order i.e. Monday, Tuesday, Wednesday then by start time.

Only problem is I can't figure out how to do this, my code currently looks like this: Which sorts alphabetically then by time:

NSString *sectionKey = nil;
switch (tab) {

case kByWeekA: {
NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"day" ascending:NO];
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"starttime" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, sortDescriptor2, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptor1 release];
[sortDescriptor2 release];
[sortDescriptors release];
sectionKey = @"day";
break;
}
case kByWeekB:{
NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"day" ascending:YES];
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"starttime" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, sortDescriptor2, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptor1 release];
[sortDescriptor2 release];
[sortDescriptors release];
sectionKey = @"day";
break;
}
default:
break;
}

Please help!

Answer

gerry3 picture gerry3 · Jan 30, 2010

I see two solutions:

  1. Create a custom comparison for your sort descriptor that looks at the "day" key and orders them as desired. See Specifying Custom Comparisons here.
  2. Make the "day" key into an integer and use an enumeration for the day values in the desired order.

UPDATE 2 Example code for option 2:

-Change the "day" attribute to a number (Int16) and add a transient (non-persistant) "dayName" string attribute.

-Add this enumeration of the week days:

typdef enum {
    kMonday,
    kTuesday,
    kWednesday,
    kThursday,
    kFriday,
    kSaturday,
    kSunday
} WeekDay;

-Set the "day" property of your managed objects to be NSNumber objects. For example:

object.day = [NSNumber numberWithInteger:kMonday];

-Implement the getter function for the transient "dayName" property:

- (NSString*)dayName {
    switch ((WeekDay)self.day.integerValue) {
        case kMonday:
            return @"Monday";
            break;
        case kTuesday:
            return @"Tuesday";
            break;
        case kWednesday:
            return @"Wednesday";
            break;
        case kMonday:
            return @"Monday";
            break;
        case kThursday:
            return @"Thursday";
            break;
        case kFriday:
            return @"Friday";
            break;
        case kSaturday:
            return @"Saturday";
            break;
        case kSunday:
            return @"Sunday";
            break;
    }
}

-In the fetch request, sort by "day" and use "dayName" as the section name key path.

UPDATE
Note: Option 1 works fine for sorting an array, but Core Data is throwing an 'NSInvalidArgumentException' exception for 'unsupported NSSortDescriptor selector: weekdayCompare:'

Example code for option 1:

// category on NSString for custom comparison
@interface NSString (WeekdayComparison)
- (NSComparisonResult)weekdayCompare:(NSString*)otherDay;
@end
@implementation NSString (WeekdayComparison)
- (NSComparisonResult)weekdayCompare:(NSString*)otherDay {
    NSArray *weekDays = [NSArray arrayWithObjects:@"Sunday", @"Monday", @"Tuesday", @"Wednesday", @"Thursday", @"Friday", @"Saturday", nil];

    NSUInteger selfIndex = [weekDays indexOfObject:self];
    NSUInteger otherDayIndex = [weekDays indexOfObject:otherDay];

    if (selfIndex < otherDayIndex) {
        return NSOrderedAscending;
    }
    else if (selfIndex > otherDayIndex) {
        return NSOrderedDescending;
    } else {
        return NSOrderedSame;
    }
}
@end

To use the new comparison method:

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"day" ascending:YES selector:@selector(weekdayCompare:)];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[sortDescriptor release];