I’m populating a tableview with data from Core Data via MagicalRecord. I want the tableview to be displayed in chronological order, sectioned by date, also in chronological order.
First, I obtain the sortDate from the transDate, from modified code I found on the web:
// Gives beginning of this day
- (NSDate *)sortDateForDate:(NSDate *)inputDate
{
// Use the current calendar and time zone
NSCalendar *calendar = [NSCalendar currentCalendar];
NSTimeZone *timeZone = [NSTimeZone systemTimeZone];
[calendar setTimeZone:timeZone];
// Selectively convert the date components (year, month, day) of the input date
NSDateComponents *dateComps = [calendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:inputDate];
// Set the time components manually
[dateComps setHour:0];
[dateComps setMinute:0];
[dateComps setSecond:0];
// Convert back
NSDate *beginningOfDay = [calendar dateFromComponents:dateComps];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
NSString *beginningOfDayText = [formatter stringFromDate:beginningOfDay];
NSLog(@"The sortDate should be %@",beginningOfDayText);
return beginningOfDay;
}
Then I assemble and save the new transaction:
-(void) assembleAndSaveTransaction
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
self.thisTransaction.transDate = [NSDate date];
self.thisTransaction.paidTo = self.noteField.text;
self.thisTransaction.forWhat = self.forWhatField.text;
// Call to obtain sortDate, method above
self.thisTransaction.sortDate = [self sortDateForDate:self.thisTransaction.transDate];
[localContext MR_saveToPersistentStoreAndWait];
}
Next, I get all transactions, grouped by the attribute “sortDate” and sorted by the attribute “transDate.”
- (void)viewDidLoad
{
[super viewDidLoad];
transactionFRC = [WMMGTransaction MR_fetchAllGroupedBy:@"sortDate" withPredicate:nil sortedBy:@"transDate" ascending:NO];
}
Then, I convert the sortDate to a string and assign it to the header title:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
NSString *sectionLabel = [formatter stringFromDate:[transactionFRC.sections objectAtIndex:section]];
NSLog(@"The sortDate is %@",[formatter stringFromDate:[transactionFRC.sections objectAtIndex:section]]);
NSLog(@"The sectionLabel should be %@",sectionLabel);
return sectionLabel;
}
Here’s how the tableview displays:
The data seems to be grouping and sorting correctly. Section headers appear in the chronologically appropriate places. But the header titles don't appear.
When I place this code in the viewDidLoad method of the VC with the relevant TableView:
NSLog(@"The header dates are as follows:\n");
for (NSDate *headerDate in [transactionFRC sections])
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
NSLog(@"The sortDate is %@",[formatter stringFromDate:headerDate]);
}
I see this readout:
2015-03-08 12:06:00.502 WheredMyMoneyGo[5374:7322757] The header dates are as follows:
2015-03-08 12:06:00.503 WheredMyMoneyGo[5374:7322757] The sortDate is (null)
2015-03-08 12:06:00.503 WheredMyMoneyGo[5374:7322757] The sortDate is (null)
2015-03-08 12:06:00.503 WheredMyMoneyGo[5374:7322757] The sortDate is (null)
2015-03-08 12:06:00.503 WheredMyMoneyGo[5374:7322757] The sortDate is (null)
I've been known to do stupid things, but I've been looking for this for 2 days without success.
Any ideas?
The problem here is that each section
in your fetched results controller isn't a date object, as you're treating it here:
for (NSDate *headerDate in [transactionFRC sections])
Instead, [transactionFRC sections]
actually returns an array of id<NSFetchedResultsSectionInfo>
objects. These contain a list of objects, an object count, and a name. In your case, the name of each section will be the date in the form of a string. To test this, replace your viewDidLoad
code with the following:
for (id<NSFetchedResultsSectionInfo> section in [transactionFRC sections])
{
NSLog(@"The sortDate is %@", section.name);
}
However, this date isn't formatted in the style you want. You really have two options:
NSDate
object, and then to reformat that date object into a string in the format you want.OR
In titleForHeaderInSection:
fetch the first object in the section in question (if there are objects in that section), and format its sort date into a string and use that. Here's an example:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
static NSDateFormatter *formatter = nil;
if (!formatter) {
formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
}
id<NSFetchedResultsSectionInfo> sectionInfo = transactionFRC.sections[section];
WMMGTransaction *transaction = [sectionInfo.objects firstObject];
NSString *sectionLabel = [formatter stringFromDate:transaction.sortDate];
NSLog(@"The sortDate is %@", transaction.sortDate);
NSLog(@"The sectionLabel is %@",sectionLabel);
return sectionLabel;
}
I've typed this without being able to test it in Xcode, but hopefully it'll get you somewhere.