Core Data Table View Section Sort by weekdays using NSSortDescriptor
Asked Answered
D

2

3

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!

Diaconicon answered 30/1, 2010 at 14:17 Comment(1)
your case A and B blocks have the same codes. I guess the B should be the case of sorting by starttime, right?Sanjak
F
13

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];
Fettle answered 30/1, 2010 at 20:33 Comment(12)
I would like to do it using the first solution but am struggling! Im trying to compare the day key to an array of day strings but can't get it to work? Any suggestions or hints of how i can implement the first solution? Many ThanksDiaconicon
I've implemented the comparison in a new class, and changed the "self" in the method call to "day" but get 'NSInvalidArgumentException', reason: 'unsupported NSSortDescriptor selector: weekdayCompare:'error. Am I implementing it in the wrong place?Diaconicon
if i went for the second solution how would i show the int as a string, if NSInteger day = 0 then display Monday... any help would be greatly appreciated!Diaconicon
The comparison method is in a "category". You can just put both its interface and implementation at the top of the implementation (.m) file where you plan to use it. You can also put it in separate files, but you have to import the header (.h).Fettle
With the second solution you would create a method to return the string given the integer (using a switch statement).Fettle
With the first solution I've added the sort both the interface and implementation at the top of the .m file where I'm using it. But I still keep getting the *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'unsupported NSSortDescriptor selector: weekdayCompare:' error. And I dont know why?Diaconicon
Your key is "day" correct? And the managed objects that you are sorting have a STRING attribute named "day"?Fettle
yea thats correct but its still not working. I've been stuck on this one area for over a week its so frustrating. I didn't think it would be so difficult to sort by day!Diaconicon
I am not sure. My code definitely works. I just tested it with objects with a string property named "day" and "day" as the sort key. Can you make an update to your question with the current code that you are using?Fettle
Hi, Would it be easier if I sent you a zip file with my project in and see if you could spot the problem?, It would really help me as it's been over a week being stuck on the same problem! Would be very appreciated! Thank you in advance.Diaconicon
Any chance you could take a look, I'm still stuck in front of the computer! Thank you, MykeDiaconicon
Hi Gerry, I can't attach the Zip to the profile email, could you send me your email address to [email protected], then I will send you back the Zip file. Thank you for all your supportDiaconicon
D
0

I was working with the same requirements for custom sorting of sections and Solution #1 worked for me very well, thanks!

One thing I'd like to add is that after adding the transient property if your app crashes mysteriously a couple of seconds after loading, you need to reset your database.

NSError *error;
NSURL *applicationDocumentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *databaseURL = [applicationDocumentsDirectory URLByAppendingPathComponent:@"My Database Name"];
[[NSFileManager defaultManager] removeItemAtPath:databaseURL.path error:&error];

Hope this helps!

Duality answered 10/11, 2012 at 21:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.