2

I am successfully sorting using an NSFetchedResultsController and a NSSortDescriptor into a table, with a section for each date, so that today's date appears first (descending date order).

However, within that section, I would like the time to be sorted in ascending order.

This is my current code without sorting by time:

//Set up the fetched results controller.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:kEntityHistory inManagedObjectContext:global.managedObjectContext];
fetchRequest.entity = entity;

// Sort using the timeStamp property..
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

fetchRequest.sortDescriptors = sortDescriptors;

//The following is from:
//http://stackoverflow.com/questions/7047943/efficient-way-to-update-table-section-headers-using-core-data-entities

NSString *sortPath = @"date.dayDate";

self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:global.managedObjectContext sectionNameKeyPath:sortPath cacheName:nil];

fetchedResultsController.delegate = self;

How would it be possible to change the code to add sorting by time ascending within this date section please?

Caroline
  • 4,875
  • 2
  • 31
  • 47

1 Answers1

3

I think you need a special comparator for this. Use initWithKey:ascending:comparator: to initialize your sort descriptor and as a comparator pass this:

^(id obj1, id obj2) {
    NSDateComponents *components1 = [[NSCalendar currentCalendar] components:NSHourCalendarUnit|NSDayCalendarUnit fromDate:obj1];
    NSInteger day1 = [components1 day];
    NSInteger hour1 = [components1 hour];

    NSDateComponents *components2 = [[NSCalendar currentCalendar] components:NSHourCalendarUnit|NSDayCalendarUnit fromDate:obj2];
    NSInteger day2 = [components2 day];
    NSInteger hour2 = [components2 hour];

    NSComparisonResult res;
    if (day1>day2) {
        res = NSOrderedAscending;
    } else if (day1<day2) {
        res = NSOrderedDescending;
    } else {
        if (hour1>hour2) {
            res = NSOrderedDescending;
        } else {
            res = NSOrderedAscending;
        }
    }
    return res;
}

This should give you the idea how this can be achieved, you will need to add the minute and second components, and also deal with the situation where hours, minutes and seconds are equal.

lawicko
  • 7,246
  • 3
  • 37
  • 49
  • Thank you - makes sense. I have since found out (I think) that NSFetchedResultsController does not support custom sort descriptors, so tomorrow I will attempt to use your code on the fetched array, and then work out how to put it back into sections. – Caroline Jul 19 '12 at 13:21
  • I'm pretty sure this should work how I described it, so try that first if you can. NSFetchedResultsController does not have much to do with the sorting process, it all happens in NSFetchRequest, specifically here: `fetchRequest.sortDescriptors = sortDescriptors;` – lawicko Jul 19 '12 at 13:37
  • Looks like it is not supported on iOS: `'NSInvalidArgumentException', reason: 'unsupported NSSortDescriptor (comparator blocks are not supported)'`. @iawicko is your answer supposed to be used on Mac OS X? – surlac Feb 04 '13 at 08:56
  • No, this class is part of the foundation framework so it should just work, but this specific method is new so you need lates OSX `Available in OS X v10.6 and later.` – lawicko Feb 04 '13 at 12:40