views:

1680

answers:

3

In my Core Data Model i've got an entity that has a date attribute and as the title suggests, i'd like to group this entity by (week)days.

The problem is, the dates are stored more or less as timestamps and i don't know how to create a predicate that is capable of grouping/filtering my entities approprioately.

I've figured out that i will probably have to do a fetch for each day, so created following method. The code were i need help with is right in the middle of it.

- (NSFetchedResultsController *)fetchedResultsController:(NSDate *)day  {
if(fetchedResultsController != nil)
 return fetchedResultsController;

// Create and Configure Request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[request setEntity:entity];

// Predicate
// pseudo code where i'm clueless is marked by "<" and ">" - start
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"DateAttribute BETWEEN <first second of day> AND <last second of day>"];
// or
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"<dayofmonth-month-year of DateAttribute> LIKE <dayofmonth-month-year of day>"];
[request setPredicate:predicate];
// pseudo code where i'm clueless is marked by "<" and ">" - end

// Sort descriptors
NSSortDescriptor *titleDescriptor = [[NSSortDescriptor alloc] initWithKey:sortDescriptorName ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:titleDescriptor];
[request setSortDescriptors:sortDescriptors]; 

// create and init fetchResultsController
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
self.fetchedResultsController = aFetchedResultsController;
fetchedResultsController.delegate = self;

//Memory
[request release];
[titleDescriptor release];
[aFetchedResultsController release];

return fetchedResultsController;

}

I'd really appreciate any help. Thanks

+2  A: 

If you want to group by weekday, the easiest thing to do is to add an attribute such as "weekday" to your entity; then you pass "weekday" as sectionNameKeyPath argument when initializing the NSFetchedResultsController. In this case there is no need to specify a predicate: you will automatically get sections for the weekdays.

If you want to group by day, you pass DateAttribute as sectionNameKeyPath argument when initializing the NSFetchedResultsController. Again, there is no need to specify a predicate: you will automatically get sections for the days.

What you are trying to do in your code differs from what you asked for. Indeed, you are not trying to get back sections (i.e. grouping by an attribute): you are instead trying to get back a single section for your tableView containing objects described by your entity satisfying a specific predicate, namely the ones whose DateAttribute falls (probably) in the current day. To achieve this, you can use the following code:

// start by retrieving day, weekday, month and year components for today
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *todayComponents = [gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:[NSDate date]];
NSInteger theDay = [todayComponents day];
NSInteger theMonth = [todayComponents month];
NSInteger theYear = [todayComponents year];

// now build a NSDate object for the input date using these components
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:theDay]; 
[components setMonth:theMonth]; 
[components setYear:theYear];
NSDate *thisDate = [gregorian dateFromComponents:components];
[components release];


// now build a NSDate object for tomorrow
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setDay:1];
NSDate *nextDate = [gregorian dateByAddingComponents:offsetComponents toDate:thisDate options:0];
[offsetComponents release];

NSDateComponents *tomorrowComponents = [gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:nextDate];
NSInteger tomorrowDay = [tomorrowComponents day];
NSInteger tomorrowMonth = [tomorrowComponents month];
NSInteger tomorrowYear = [tomorrowComponents year];

[gregorian release];


// now build the predicate needed to fetch the information
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"DateAttribute < %@ && DateAttribute > %@", nextDate, thisDate];

This predicate will retrieve exactly all of the objects whose DateAttribute falls within the current day. Hope this helps.

unforgiven
thanks for your comprehensive response!"If you want to group by day, you pass DateAttribute as sectionNameKeyPath argument when initializing the NSFetchedResultsController. Again, there is no need to specify a predicate: you will automatically get sections for the days."it would be great if that worked, but when doing so, it groups by the value of the DateAttribute (which includes time, e.g. "2009-07-02 20:51:27 -0400")p.s.:my ultimate goal is to get a list of weekdays and when clicking one of them, all entities connected with that day open in another tableview.
gabtub
You can achieve this by storing in your entity the DateAttribute without the time using the same technique I have shown in my example code: starting from a NSDate object (your DateAttribute), you first extract its date components and then build another NSDate object using these components (therefore it does not contain the time). It is this final NSDate object that you store in your entity. Then, retrieving the objects on the basis of their day works as explained.
unforgiven
gabtub
+1  A: 

Hi @gabtub I was actually looking at your question and i had a question of the same kind. What I wanted to do was to divide my table into sections by date and not timestamp as u mentioned. So what i did is added a new method in my class that extends NSManagedObject ( which is the entity i am fetching) that method returns a formatted date as such:

- (NSString *)transactionDay{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
return [dateFormatter stringFromDate:self.date];}

then changed my fetchedResultController to be:

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"transactionDay" cacheName:nil];

And everything worked as a charm.

Check out the link to see more details. http://www.IPHONE4GAPP.NET/superdb-core-data-app-with-sections.html

Cocoa student
interesting, thank you!
gabtub
A: 

@ Cocoa student:

When I try as you suggest I get this error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath transactionDay not found in entity <NSSQLEntity MyEntity id=1>'

Is there something else I have do consider?

(For some reason I cannot reply directly, so I have to post this as answer to the original question, sorry)

Anonymous
Got it. I had used "transactionDay" in one of my sort descriptors, which was causing the error -_-
Anonymous