NSFetchedResultsController update every minute with observable NSDate of today? - core-data

I have a list of results showing on the UI for the current NSDate. Every minute, I need this list and another field to update (although a change may not occur every minute).
I am using an NSFetchedResultsController with an NSPredicate and a static variable holding the NSDate at the time.
Now I could simply reset the NSFetchedResultsController every minute, but with an observable coredata set that seems a little crude.
Is there a way to make that NSDate variable observable, such that coredata will reevaluate the NSPredicate when it's updated?
var today: NSDate = NSDate()
predicate: NSPredicate(format: "startTime > %# AND endTime < %#" /* AND classCodeNumber != nil" */, today.startOfDay(), today.endOfDay())!...
With passing time, this predicate should change the set of data shown.

Related

Need to write a predicate to search for a date in a core data object's array property (in my case array of dates)

I need to fetch an object using Core Data. The object has a property datesArray(Array of NSDate objects stored as NSData) which I use to store array of dates. I need to check if the array contains todays date and then use the object.
NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:#"MyEntity"];
NSError * error;
NSArray * fetchedArray = [context executeFetchRequest:request error:&error];
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"entity.datesArray CONTAINS %#",[NSDate date]];
for (MyEntity * entity in fetchedArray) {
NSMutableArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:entity.datesArray];
[array filterUsingPredicate:predicate];
if (array.count >0) {
[_myMutableArray addObject:entity];
}
}
You really should not be storing dates like this. You are losing the value of using Core Data. If you have an array of something then that should be on the other side of a relationship which you can then retrieve efficiently from the underlying persistent store.
I suspect that your predicate lacks precision as a date object is down to the nanosecond. If you are looking to match something from "today" then you need to work on something with less precision. Perhaps a string in a specific format or store it as a number and then search within a range (less than X and greater than Y type of search).
Again, storing the actual dates in managed objects makes this question much easier but you are still going to be dealing with a precision problem.

How to Format NSDate in the Model Layer

I have a NSDate that I want to return as formatted like 10:00PM.
I have the date formatter working.
I'm wondering how I can make it so that whenever I fetch that date it comes back formatted as desired.
The NSDate in question in a daily start time for an activity that is store in an NSManagedObject
subclass.
#implementation Schedule
#dynamic repeat;
#dynamic start;
-(NSString*)amPMFormat
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"h:mm a"];
return [dateFormatter stringFromDate:self.start];
}
#end
I'm using a keypath to fill in a TableViewCell. The object bound to the cell is a Ritual which knows a Schedule. My thought was to call the method amPMFormat using the keypath and just return the formatted date as a string but that doesn't work. This code is a cell created using Sensible TableView. The cell has a STEP bound to it, STEP has a SCHEDULE, and SCHEDULE has a start property which is an NSDate that only has hours and minutes saved into it.
SCCustomCell *descrCell = [SCCustomCell cellWithText:nil objectBindingsString:#"1:schedule.start.amPMFormat;3:desc" nibName:#"RitualCell"];
You've munged the Model and the View parts of your program.
The date (self.start) is an instant in time. You can represent that date in any of a multitude of calendars, languages, locale-specific formats, and precision. It's still a single instant in time.
The formatter is a way to build a standard string representation of that instant. If you want the date formatted a particular way "whenever [you] fetch that date", you can use -awakeFromFetch: to populate a read-only property. Or perhaps a class method on Schedule, +formattedStringForDate:, which formats an NSDate appropriately and returns an NSString.
Your cryptic second snippet mentions "bindings". Are you using Cocoa Bindings and writing an OS X app? If so, you can put a date formatter on the NSTextField instance in your XIB.

NSPredicate without consider time component

From my table I want select all rows of a particular date without considering the time component of NSDate.Please any one suggest a NSPredicate to achieve this ?
NSDate describes an absolute point in time and does not have "day" or "time" components.
The same is true for a Core Data "Date" attribute, which is stored as the number of seconds
since 1 January 2001, GMT in the database.
What you probably want is to fetch all objects where some "Date" attribute falls into the
interval given by the start of a given day and the start of the next day.
Therefore you have to compute these dates first, using NSCalendar methods:
NSDate *yourDate = ...;
NSDate *startOfDay, *startOfNextDay;
NSTimeInterval lengthOfDay;
NSCalendar *cal = [NSCalendar currentCalendar];
[cal rangeOfUnit:NSDayCalendarUnit startDate:&startOfDay interval:&lengthOfDay forDate:yourDate];
startOfNextDay = [startOfDay dateByAddingTimeInterval:lengthOfDay];
Then use a predicate that fetches all objects where the attribute falls between
these two values:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"date >= %# AND date < %#",
startOfDay, startOfNextDay];

Limit Core Data Entities Shown In UITableView row

I think I'm just missing something obvious here, but it's one of those frustrating things that's somehow eluding me.
I have a Core Data Entity called ProjectEntry. The ProjectEntry objects are displayed in uitableviews, using various attributes, arranged by date (attributes include things like "dateAsNSDate"[NSDate], "month"[NSString], "year"[NSString], "dayOfWeek"[NSString]).
I'm using an NSFetchedResultsController to populate the table views.
When I initially create and save the ProjectEntry object, the "dateAsNSDate" attribute is parsed and converted into various NSStrings. One string, also an attribute, is called "concatMonthAndYear". It takes the "month" and "year" strings and just joins them. So I get things such as "January 2014", "February 2015", etc.
I use the "concatMonthAndYear" as my cell.textLabel.text string to display in my tableview cells.
I use the NSDate attribute to sort the tableview rows (sortDescriptor), and the "year" attribute as my section headers (sectionNameKeyPath).
So right now, I'd have a tableview section called "2014", with tableview rows each representing a Core Data object, named things like "January 2014", February 2014", etc, in said section.
I can tap on one of those rows, segue to another tableview, and list all objects created in January 2014, for example, by using an NSPredicate on the second tableview.
However, on my first tableview, each Core Data object created is represented by its own tableview row. So I'll get multiple rows reading "January 2014" or "May 2015" or whatever. They're valid saved objects, and I want them, but I'd like to prevent a new row from being created if that "concatMonthAndYear" already exists. If a row titled "January 2014" already exists, I don't want a new row created. I want the new Core Data object stored, just not a new tableviewrow representing it. I only need one row with "January 2014", for example, to segue into a table listing ALL the entities from January 2014.
I know how to use an NSPredicate to get ALL the January 2014 objects into the second table, but how do I get JUST ONE object into the first table?
Is NSPredicate not the right device for that? Should I be somehow preventing a new cell from being created in the UITableView delegate methods? Each tableview row should be unique, and I'm stuck on whether it should be handled with the NSFetchedResults controller or in the tableview delegate methods?
Or some other way?
Can someone point in the right direction?
EDITED TO INCLUDE CODE:
- (void)setupFetchedResultsController
{
// 1 - Decide which Entity
NSString *entityName = #"ProjectEntry";
NSLog(#"Setting up a Fetched Results Controller for the Entity named %#", entityName);
// 2 - Request Entity
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
[request setReturnsDistinctResults:YES];
[request setResultType:NSDictionaryResultType];
[request setPropertiesToFetch:#[#"monthYearTableSecHeader", #"year"]];
// 3 - Filter it
//request.predicate = [NSPredicate predicateWithFormat:#" "];
// 4 - Sort it
request.sortDescriptors = [NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:#"year"
ascending:NO],
[NSSortDescriptor sortDescriptorWithKey:#"dateAsNSDate"
ascending:YES
selector:#selector(localizedCaseInsensitiveCompare:)], nil];
//5 - Fetch
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"year"
cacheName:nil];
[self performFetch];
}
You could use
[fetchRequest setReturnsDistinctResults:YES];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setPropertiesToFetch:#[#"concatMonthAndYear", #"year"]];
This will cause the fetch request to return distinct dictionary objects corresponding to "January 2014", etc. objects.
However, you cannot use a fetch request controller's delegate methods (to hear of updates to the data).
If you need to hear updates, I suggest you add a layer of indirection to your data, where MonthEntry is an object representing yearly months and have a one to many relationship with ProjectEntry, which is your normal entity. This way, you can set the fetch request entity to MonthEntry.

CoreData predicate by date

I have a coreData model already setup and data added to it. I want to search for all items from the last 30 days, and then add together a total number of units.
Here's what I got :-
- (void) calculateThirtyDayValues {
NSDate *endDate = [NSDate date];
NSTimeInterval timeSinceRefDate = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval lastThirtyDays = timeSinceRefDate- 2592000;
NSDate *startDate = [NSDate dateWithTimeIntervalSinceReferenceDate:lastThirtyDays];
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"(date >= %#) AND (date <= %#)", startDate, endDate];
}
Basically I have create an NSDate object set todays date, and then created another NSDate object set to 30 days before today. Then trying to predicate all objects from the start date until the present date.
I am getting results returned, but they don't seem to be really matching up with what the totals should be for the past 30 days. It appears to just be returning everything!
Any ideas?
Your predicate seems to be OK, but your date code is incorrect, for a couple of reasons.
[NSDate date] returns the current date, with sub-millisecond precision. So if you create the predicate at 4:15:37 PM local time, this predicate would not find any objects with a date of 5:37:42 PM local time. If you want down-to-the-second precision like that, then you're probably OK. But if you want granularity to a different calendar unit (such as by day), then you need to do more work.
Not every day has 86,400 seconds in it. Thus your attempt to subtract (30*86400) is subtly wrong. You should be letting the calendar object do the math for you:
NSDate *endDate = ...;
NSDateComponents *diff = [[NSDateComponents alloc] init];
[diff setDay:-30];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *startDate = [calendar dateByAddingComponents:diff toDate:endDate options:0];

Resources