iPhone Core Data fetching date manipulations - iphone

I'm new to developing for the iPhone and I'm using Core Data for my data management. My managed objects have a property called creationDate and I need to have a list of all distinct dates that are in the database. To reduce the overhead I set
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:#"creationDate"]];
because that's all that's needed.
I know I can set [fetchRequest setReturnsDistinctResults:YES]; to get the distinct dates, but how can I take only the date part of an NSDate in a fetch request?
thanks,
Thomas
P.S. In SQL this would look something like: SELECT DISTINCT DATE(creationDate) FROM events;

By "date part of an NSDate" I assume you mean as distinct from the time? You can't directly express that for the purposes of distinct results if the entry in the store has the time encoded. What you can do is split the creationDate in your model to a two properties, date and time, and the normalize all the dates to a single time (or if you don't care about the time you can just throw out the time). If you actually still need the time it is there, but you can do queries purely against the date.
If your entity has its own subclass you can do that by writing a custom setter that takes the data, extracts the components via NSDateComponents, and reassembles those into a date via NSCalendar.
Yes, it seems like it should be simpler to deal with dates, but it is necessary to take a somewhat roundabout path.

Related

Saving to CoreData - Add to Top

All,
Is it possible to save to the top of the CoreData? If so, how?
For example, every time something is added to the data store, I want it to be inserted at the top. This way, when the results are fetched they would come back sorted by most recent first without having to save the NSDate and fetch with a predicate. Here is a crude example:
Most recent
Earlier
Yesterday
Last Week
Thanks,
James
What is the "top"?
Core Data does not assign any particular order to the objects it stores. If you want to impose some order on the objects, add an attribute to the entity that you want to be ordered and then sort on that attribute when you fetch the objects. So, you could add a serialNumber attribute that always increases. Sorting on that serial number would order the objects.
Add a creationDate in the model, and the following code to your custom implementation of the object:
- (void)awakeFromInsert {
[self setPrimitiveCreationDate:[NSDate date]];
}

Efficient way to update table section headers using Core Data entities?

Im using a NSFetchedResultsController for my UITableView which displays a bunch of events im storing in core data.
What i am trying to do is group the table by relative date (ie Today, Tomorrow, This Week, etc..). Each event has a start date and i tried creating a transient property in the event entity called sectionIdentifier which converts the date into a relative date as mentioned above like so:
- (NSString*)sectionIdentifier
{
[self willAccessValueForKey:#"sectionIdentifier"];
NSString *tmp = [self primitiveSectionIdentifier];
[self didAccessValueForKey:#"sectionIdentifier"];
if (!tmp)
{
tmp = [Utility formattedDateRelativeToNow:self.startTime];
[self setPrimitiveSectionIdentifier:tmp];
}
return tmp;
}
The problem is that it obviously only does this once and doesn't update itself unless the date is changed which i dont really expect. I have thought of overriding the getStartDate accessor to update the sectionIdentifier although this seems a little heavy handed and inefficient as it would perform this update every time i access that property
Any ideas?
The best method for doing this is rather counterintuitive. Instead of changing the fetched results controller or anything in Core Data, you extend NSDate with a category to have a keyname/method that returns a value based on the appropriate date calculation. You then include the keyname/method in the fetched results controller sectionNameKeyPath.
See this previous answer for an example of how to extend NSDate with keyname/methods like today, yesterday, tomorrow etc.
To use this, you would just take on the method to a date attribute of the entity the fetched results controller fetches like so:
NSFetchedResultsController *frc=[[NSFetchedResultsController alloc] initWithFetchRequest:aFetch
managedObjectContext:aMoc
sectionNameKeyPath:#"startdate.yesterday"
cacheName:nil];
... and the sections will appear automatically.
I think you will need to update you section headers as frequently as the smallest duration for which you are displaying a section (which seems to be one day). I would have proceeded in the following fashion-
1) Save the current time-stamp in applicationDidFinishLaunching using NSUserDefaults, etc.
2) Next time the application is launched, determine the difference between the current time-stamp & the one saved.
3) If the difference is more than your smallest duration (one day), regenerate your table, including section headers, as Today would have become Yesterday & Yesterday may have become last week.
HTH,
Akshay

Predicate for selecting item with subset of relation

I have a DB with a list of days ('Day' objects).
Each day has a list of events (one-to-many)
How do I write a fetch predicate in order to fetch all day objects where name=='Monday' and only include the events where the time is > aStartTime and time < aEndTime?
Or in other words....
I want an array of 'Monday' objects where day.events only contains the events for a certain time interval.
You can't without adding new Day objects; it goes against the whole point of Core Data (object graph/change management). And if each event can only have one Day, it gets messy.
Alternatively, you can return some sort of "proxy" Day objects, but that won't quite do the same thing (it might be closer to what you're looking for, though).
Alternatively, in each event, store a number between 0 and 60*60*24*7, do the query, and sort the results however you like.
Alternatively, tell us what you're actually trying to achieve and we might be able to give a better answer.

Core Data Fetched Results Order

I"m working with a core data model of Employees. Each employee is assigned a building and a department. I am returning everyone in building 1 with the predicate, building == 1 and using the sectionNameKeyPath parameter to break the result set down into groups by department.
Right now I have a sort descriptor ordering the departments alphabetically, but is there a way to ignore sorting them alphabetically and organize them in my own way, like engineers first, security second so on and so forth? I'm still getting used to the terminology and there's probably something I'm overlooking.
Thanks,
Note that the sortDescriptors property of the fetched results controller is an array, so you can set multiple sort descriptors which will be used in the order you specify them (e.g. first by department.name, then by lastName, then by firstName).

Debugging Core Data managed objects with predicates

My application has the data models a little bit complicated. I need to debug a fetch request with different predicates.
Is there any fast way to see different results for different predicates? I am tired with changing only one predicate and I have to start again my navigation application with nearly 10 steps before.
An example of these predicates that I would like to see the results:
item = %#
item = %# AND quantity = %#
item = %# OR (startdate >= %# AND enddate <= %#)
etc...
As using Core Data, I can not see the database with its' values to do some SELECTs.
You can add logic in your code to change the predicate and fetch again (maybe add a temporary button to trigger this and cycle through your various predicates).
You may also be interested in viewing the data in your SQLite file. Check out this answer to How view data stored in Core Data?
I'm not sure if it is any help, but if you want to quickly see the return results, go into gcc command line and write
po <name of array with results>
so if the array is items
po items
Will give all the returned results printed nicely in the console
To view your data inside of SQLite for free, just get FireFox. Then install SQLite Manager.
Cheers.
-RoLYroLLs
http://iphone.rolyrolls.com