1

I know how to sort Core Data objects in a tableview by NsDate, but this by default seems to create a new section for each object. I want to sort them by a medium formatted date with NSDateFormatter. How would I do this?

For example, if I have 3 objects created on the same day, I want them to be in the same section with the section title being that Day, no time needed.

Each object has an NSDate property. Thanks for your help.

This is the code I have in fetchedResultsController with rgeorge's suggestions. What am I missing here?

- (NSFetchedResultsController *)fetchedResultsController {

if (fetchedResultsController != nil) {
    NSLog(@"get old fetched controller");

    return fetchedResultsController;
}

else{
    NSLog(@"get new fetched controller");
}

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"InTextEntity" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];

NSSortDescriptor *dateDescriptor = [[NSSortDescriptor alloc] initWithKey:@"dateModified" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:dateDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];


NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"mediumFormattedDate" cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;

NSError *error = nil;
if (![fetchedResultsController performFetch:&error]) {

    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

}

return fetchedResultsController;

}

W Dyson
  • 4,604
  • 4
  • 40
  • 68

2 Answers2

2

(I'll write this up assuming you're using an NSFetchedResultsController to drive your tableview. If you're not, I recommend checking it out.)

An interesting feature of NSFetchedResultsController's sectioning abilities: although the property you sort on must be a modeled property (because sqlite does the actual sorting), the property you group the sections with need not be. The only requirement is that the grouping be consistent with the ordering. (i.e., sorting by the sort property will put the objects with matching group properties next to each other.)

So just add something like this to your modeled object class:

// in interface
@property (nonatomic, readonly) NSString *mediumFormattedDate;

// in impl
-(NSString *)mediumFormattedDate
{
  // this can be fancier if you need a custom format or particular timezone: 
  return [NSDateFormatter localizedStringFromDate:self.date
                                        dateStyle:NSDateFormatterMediumStyle
                                        timeStyle:NSDateFormatterNoStyle];
}

(no need to mention mediumFormattedDate in the .xcdatamodel at all.)

Then go ahead and sort your objects by the date property, but group them by your new property. When you create your NSFetchedResultsController, do so along these lines:

NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"MyFancyEntity"];
NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"date"
                                                     ascending:YES];
[fr setSortDescriptors:[NSArray arrayWithObject:sd]];
NSFetchedResultsController *frc =
[[NSFetchedResultsController alloc] initWithFetchRequest:fr
                                    managedObjectContext:myManagedObjectContext
                                      sectionNameKeyPath:@"mediumFormattedDate"
                                               cacheName:nil];
// then do stuff with frc

That's all it takes! I've done this in a few apps to get date grouping and it works well.

rgeorge
  • 7,385
  • 2
  • 31
  • 41
  • Thanks very much! I will try this in the morning and let you know how it goes! – W Dyson Jun 20 '12 at 03:05
  • One question, what is setting the value of self.date in mediumFormattedDate? – W Dyson Jun 20 '12 at 19:56
  • This is the error I'm getting: the entity InTextEntity is not key value coding-compliant for the key "mediumFormattedDate".' – W Dyson Jun 20 '12 at 20:50
  • 1
    It maybe sounds as if your instances of InTextEntity aren't actually instances of whatever class you added mediumFormattedDate: to? Check your xcdatamodel. I should have mentioned that this technique requires custom entity classes - using plain NSManagedObjects won't work. I can't tell much more without more detail. – rgeorge Jun 20 '12 at 22:22
  • as for "self.date": "self" is the managed object, and "date" is a guess at the name of the date property you're sorting by. Substitute in the actual name you use. – rgeorge Jun 20 '12 at 22:24
  • Oi. I was adding the mediumFormattedDate getter and properly to the tableView class. Once I fixed this, it all works great. Thanks very much! – W Dyson Jun 22 '12 at 19:03
0

Sounds like you're setting the section index on the fetched results controller to be your date property, which seems undesirable.

Instead you should probably be computing the section index yourself, and sorting by date. You can accomplish this in either your data model or by computing the sections manually in code.

For example, you could add a property to your managed object model called "Day" and set that to whatever value you want to use (you don't specify if its something like Monday or an actual date like 21).

You can then pass that property to the fetched results controller.

Alternatively you could implement the sections yourself, days are easy, its Monday-Sunday. Dates are a bit harder, 1-28,30,31 depending on what month it is. Then use an appropriate NSPredicate / NSFetchRequest to get the count of the items in each section.

ImHuntingWabbits
  • 3,827
  • 20
  • 27