display the returned values in section header - objective-c

i am working on an expense tracker kind of application.i am able to store and retrieve sorted data perfectly using coredata.
i am storing date.i am able to retrieve date in a sorted order.but i want to the date in the section header and related data in that table.
ex:
Dec 31st 2011 ---------> Section Header
xxxxxxx yyyyyy ----->cell with labels
Jan 1st 2012---------->Section Header
xxxxxxx yyyyyy ------>cell with labels.
i am able to receive the dates in a sorted order.but how to display them in a section header in a sorted order and how to declare the number of sections in tableView-noOfSections method?
//Code i used for retrieving data.
- (void)viewDidLoad
{
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"NewExpense" inManagedObjectContext:context];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSSortDescriptor *date = [[NSSortDescriptor alloc]initWithKey:#"date" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:date,nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setEntity:entityDesc];
NSError *error;
self.listOfExpenses = [[context executeFetchRequest:fetchRequest error:&error]retain] [fetchRequest release];
[super viewDidLoad];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;// as of now i have taken one.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
[self.listOfExpenses count]; 
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//labels are created and added to the cell's subview.
NSManagedObject *records = nil;
records = [self.listOfExpenses objectAtIndex:indexPath.row];
self.firstLabel.text = [records valueForKey:#"category"];
NSString *dateString = [NSString stringWithFormat:#"%#",[records valueForKey:#"date"]];
NSString *dateWithInitialFormat = dateString;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss Z"];
NSDate *date = [dateFormatter dateFromString:dateWithInitialFormat];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSString *dateWithNewFormat = [dateFormatter stringFromDate:date];
self.secondLabel.text = dateWithNewFormat;
NSString *amountString = [NSString stringWithFormat:#"%#",[records valueForKey:#"amount"]];
self.thirdLabel.text = amountString;
totalAmount = totalAmount + [amountString doubleValue];
}

Date in the section header is a bit tricky, but there is very good sample code from Apple out there which I am using in one of my current apps successfully. Look at DateSectionTitles.
In short, you need to use a NSFetchedResultsController and define the sectionNameKeyPath with a separate property of your entity (the date itself won't do because it is accurate to the second). In numberOfSections you will have to return whatever the fetched results controller gives you, not 1 as above. numberOfRowsInSection will have to be adjusted as well, you get the idea.
Apple calculates a primitive date and reconstructs it when it has to format the string for the section header. All pretty straight forward. Just follow the sample code and you have solved this in no time.

You can use NSSortDescriptor:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
...
NSSortDescriptor * sort = [[NSSortDescriptor alloc] initWithKey:sortingKey ascending:ascending];
NSArray * sortDescriptors = [NSArray arrayWithObject: sort];
[request setSortDescriptors:sortDescriptors];
as sortingKey you will pass in your case date.
See docs on NSSortDecsriptor here:
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSSortDescriptor_Class/Reference/Reference.html

Related

Sorting in Core Data with Multiple Values

i have list of brands stored in Core Data, each brand is associated with multiple contents. The contents have a flag called downStatus which is used to denote whether a content is downloaded or not. The following method is used to fetch all the brands from Core data sorted with brand name
-(void)getDownloadedBrands{
AppDelegate *aAppDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSMutableArray *aBrands = [[NSMutableArray alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"Brand" inManagedObjectContext:aAppDelegate.managedobjectcontext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
NSSortDescriptor *sort=[[NSSortDescriptor alloc]initWithKey:#"brandName" ascending:YES];
//NSSortDescriptor *sort1=[[NSSortDescriptor alloc]initWithKey:#"downStatus" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObjects:sort, nil]];
aBrands =(NSMutableArray *)[aAppDelegate.managedobjectcontext executeFetchRequest:request error:nil];
[request release];
[sort release];
NSLog(#"%#",aBrands);
brands = [[NSMutableArray alloc]initWithArray:aBrands];
aAppDelegate.dbBrandArr = brands;
[self loadGridView];
}
Now i want to sort using the downStatus which is in the Content. So it will be like, downloaded brands in Alphabetical Order and then Un-Downloaded brands in Alphabetical order. The downStatus takes two values 1 for downloaded 0 for not downloaded. Please help.
One way to do it is by making 2 fetchRequests to CoreData using the NSPredicate with value 1/0 on downStatus property and using the same alphabetical sortDescriptor.
Now create a new Array by adding the 0 array to the 1 array. In your code it would look something like this:
-(void)getDownloadedBrands{
AppDelegate *aAppDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
//2 arrays
NSMutableArray *aBrands0 = [[NSMutableArray alloc] init];
NSMutableArray *aBrands1 = [[NSMutableArray alloc] init];
//set entity en make requests
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Brand" inManagedObjectContext:aAppDelegate.managedobjectcontext];
NSFetchRequest *request0 = [[NSFetchRequest alloc] init];
NSFetchRequest *request1 = [[NSFetchRequest alloc] init];
[request0 setEntity:entity];
[request1 setEntity:entity];
//create sortDescriptor alphabetically
NSSortDescriptor *sort=[[NSSortDescriptor alloc]initWithKey:#"brandName" ascending:YES];
//create predicates on downStatus property
NSPredicate *predicate0 = [NSPredicate predicateWithFormat:#"downStatus == %#", [NSNumber numberWithBool:0]];
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:#"downStatus == %#", [NSNumber numberWithBool:1]];
//set predicates to the requests
[request0 setPredicate:predicate0];
[request1 setPredicate:predicate1];
//set sortDescriptor to both requests
[request0 setSortDescriptors:[NSArray arrayWithObjects:sort, nil]];
[request1 setSortDescriptors:[NSArray arrayWithObjects:sort, nil]];
//fetch arrays with downStatus 1/0
aBrands0 =(NSMutableArray *)[aAppDelegate.managedobjectcontext executeFetchRequest:request0 error:nil];
aBrands1 =(NSMutableArray *)[aAppDelegate.managedobjectcontext executeFetchRequest:request1 error:nil];
//release requests // NOT USING ARC??
[request0 release];
[request1 release];
[sort release];
//log results
NSLog(#"aBrands0: %#",aBrands0);
NSLog(#"aBrands1: %#",aBrands1);
//add object 0 array to 1 array
NSArray *combinedArray = [aBrands1 arrayByAddingObjectsFromArray:aBrands0];
//copy array to brands
brands = [[NSMutableArray alloc]initWithArray:combinedArray];
//set property on appDelegate
aAppDelegate.dbBrandArr = brands;
//reload tableView
[self loadGridView];
}
-- edit, adding answer for NSDictionary with downStatus key
-(void)getDownloadedBrands{
AppDelegate *aAppDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSMutableArray *aBrands = [[NSMutableArray alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Brand" inManagedObjectContext:aAppDelegate.managedobjectcontext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
NSSortDescriptor *sort=[[NSSortDescriptor alloc]initWithKey:#"brandName" ascending:YES];
//NSSortDescriptor *sort1=[[NSSortDescriptor alloc]initWithKey:#"downStatus" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObjects:sort, nil]];
aBrands =(NSMutableArray *)[aAppDelegate.managedobjectcontext executeFetchRequest:request error:nil];
NSMutableArray *aBrands0 = [[NSMutableArray alloc] init];
NSMutableArray *aBrands1 = [[NSMutableArray alloc] init];
for (NSDictionary *dict in aBrands) {
if ([dict valueForKeyPath:#"downStatus"] == YES)
{
//add to 1 array
[aBrands1 addObject:dict];
}
else
{
//add to 0 array
[aBrands0 addObject:dict];
}
}
//sort arrays
NSArray * array1 = [aBrands1 sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
NSArray * array0 = [aBrands0 sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
NSArray * allArray = [aBrands1 arrayByAddingObjectsFromArray:aBrands0];
//combine arrays
//copy array to brands
brands = [[NSMutableArray alloc]initWithArray:combinedArray];
//set property on appDelegate
aAppDelegate.dbBrandArr = brands;
//reload tableView
[self loadGridView];
[request release];
[sort release];
NSLog(#"%#",aBrands);
}
If you plan to use the fetch result in a UITableViewController, you could use the sectionNameKeyPath of your fetchedResultsController for the downStatus and keep your sort descriptor for the brand name. Can look like this:
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"customSectionTitle" cacheName:nil];
Place this in the header file of your NSManagedObject :
-(NSString*)customSectionTitle;
And this in .m :
-(NSString*)customSectionTitle{
if ([downStatus boolValue] == YES) {
return #"Downloaded";
}
else {return #"Not Downloaded";}
}
If you do not plan to use a fetchedResultsController, just sort first by downStatus and then by brand name.

Passing fetchedResultsController object to child returns nil later

I have a UITableView for my iPad app which when you tap on a row, will display a popOver with another table in it with one section. The popOver table section header is dependant on values from the fetchedResultsController on the main UITableView controller. When the popover first loads the information is correct. However, after the user taps on a cell in the popover, it goes to another view inside the popover that will allow you to edit data. Once you save, I call a delegate method to refresh the main UITableView while the popover stays shown. Then the view where the user edited the data is dismissed so it goes back to the popover UITableView. At this point the fetchedResultsController that was passed in as slot is now nil. I cannot figure out why it is doing this.
Why is the slot now nil in SlotViewController and how do I prevent it?
#interface
NSFetchedResultsController *fetchedResultsController;
Main UITableView
#synthesize fetchResultsController = _fetchedResultsController;
- (NSFetchedResultsController *)fetchedResultsController {
/*
Set up the fetched results controller.
*/
if (_fetchedResultsController != nil) {
NSLog(#"RETURNING FETCHEDRESULTS");
return _fetchedResultsController;
}
NSLog(#"Should only be called once");
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = nil;
if ([[dataObj.client objectForKey:#"appt_method"] integerValue] == 2) {
entity = [NSEntityDescription entityForName:#"Slots" inManagedObjectContext:[[CoreDataHelper sharedInstance] managedObjectContext]];
} else {
entity = [NSEntityDescription entityForName:#"Appointments" inManagedObjectContext:[[CoreDataHelper sharedInstance] managedObjectContext]];
}
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:nil];
//[fetchRequest setIncludesPendingChanges:YES];
// Set the batch size to a suitable number.
//[fetchRequest setFetchBatchSize:20];
// Sort using the date / then time property.
NSSortDescriptor *sortDescriptorDate = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:YES];
NSSortDescriptor *sortDescriptorTime = [[NSSortDescriptor alloc] initWithKey:#"start_time" ascending:YES selector:#selector(localizedStandardCompare:)];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptorDate, sortDescriptorTime, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Use the sectionIdentifier property to group into sections.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[[CoreDataHelper sharedInstance] managedObjectContext] sectionNameKeyPath:#"date" cacheName:nil];
// aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Slots *selectedSlot = [_fetchedResultsController objectAtIndexPath:indexPath];
SlotViewController *slotView = [parentNav.storyboard instantiateViewControllerWithIdentifier:#"SlotViewController"];
[slotView setSlot:selectedSlot];
CGRect rect = [self rectForRowAtIndexPath:indexPath];
rect.size.width = rect.size.width / 3;
UINavigationController *navBar = [[UINavigationController alloc] initWithRootViewController:slotView];
popOver = [[UIPopoverController alloc] initWithContentViewController:navBar];
popOver.delegate = self;
//[popOver setPopoverContentSize:CGSizeMake(320, 460) animated:YES];
[popOver presentPopoverFromRect:rect inView:self permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
SlotViewController / popover UITableView
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSLog(#"slot: %#", _slot.date);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyyMMdd"];
NSDate *currDate = [dateFormatter dateFromString:_slot.date];
[dateFormatter setDateFormat:#"h:mma"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
NSDate *midnight = [NSDate dateWithTimeIntervalSince1970:0];
NSDate *startTimeDate = [midnight dateByAddingTimeInterval:[_slot.start_time integerValue] * 60];
NSDate *endTimeDate = [midnight dateByAddingTimeInterval:[_slot.end_time integerValue] * 60];
NSString *startTime = [dateFormatter stringFromDate:startTimeDate];
NSString *endTime = [dateFormatter stringFromDate:endTimeDate];
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[dateFormatter setDateFormat:#"E, MMM dd, yyyy"];
return [NSString stringWithFormat:#"%# %#-%#",[dateFormatter stringFromDate:currDate], startTime, endTime];
}
I'm able to get it working properly by changing the didSelectRowAtIndexPath code from
Slots *selectedSlot = [_fetchedResultsController objectAtIndexPath:indexPath];
to
Slots *selectedSlot = [Slots disconnectedEntity];
Slots *tmpSlot = [_fetchedResultsController objectAtIndexPath:indexPath];
for (id key in tmpSlot.entity.attributesByName) {
[selectedSlot setValue:[tmpSlot valueForKey:key] forKey:key];
}
disconnectedEntity
is a Core Data managed context that is not tied to an object.
+ (id)disconnectedEntity {
NSManagedObjectContext *context = [[CoreDataHelper sharedInstance] managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Slots" inManagedObjectContext:context];
return [[self alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:nil];
}
However I am wondering why the original code will not work. I am assuming that it is because the fetchedResultsController is passing the reference to selectedSlots so when fetchedResultsController updates, the reference no longer exists?

NSSortDescriptor should sort NSDates

It appears NSSortDescriptor should be a fairly easy class to work with.
I have stored in CoreData an entity with an attribute of type NSDate appropriately named #"date". I am attempting to apply a sort descriptor to a NSFetchRequest and it doesn't appear to be returning the results I had hoped for.
The result I am hoping for is to simply arrange the dates in chronological order, and instead they are returned in the order for which they were added to CoreData.
Perhaps you can offer guidance?
Is the parameter 'ascending' what controls the sort?
Some Code:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Data" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entityDesc];
[fetchRequest setFetchBatchSize:10];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
Separate sort routines (functions or blocks) look like overkill to me. I am routinely sorting Core Data entities by date attribtues just with the sort descriptor method you show in your code. It works perfectly every time.
Clearly, there must be some other mistake.
Check if the type is set correcly in your managed object model editor, and in the class file (Data.h, in your case).
Also, check if you are not manipulating this attribute so that the creation order ensues.
Also, make sure you are not mixing up this attribute with another attribute of type NSDate.
Here is more information on NSSortDescriptors
Or if you want to sort an array of dates after getting them for coreDate:
//This is how I sort an array of dates.
NSArray *sortedDateArray = [dateArray sortedArrayUsingFunction:dateSort context:NULL];
// This is a sorting function
int dateSort(id date1, id date2, void *context)
{
return [date1 compare:date2];
}
Here is code straight from apple for sorting integers (just modify to sort dates):NSComparator
NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {
if ([obj1 integerValue] > [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
if ([obj1 integerValue] < [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
Add timestamp - String type field in CoreData entity
creationDate
during insertion of the record
NSManagedObject *newCredetial = [NSEntityDescription insertNewObjectForEntityForName:#"Name" inManagedObjectContext:context];[newCredetial setValue:[self getDate] forKey:#"creationDate"];
date function
- (NSString *)getDate{
NSDate *date = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
formatter.dateFormat = #"ddMMyyyyhhmmssss";
return [formatter stringFromDate:date];}
and Use Short Description during Fetching module
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest1 = [[NSFetchRequest alloc] initWithEntityName:#"Name"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"creationDate" ascending:NO];
[fetchRequest1 setSortDescriptors:#[sortDescriptor]];
arrNameInfo = [[managedObjectContext executeFetchRequest:fetchRequest1 error:nil] mutableCopy];
just change samle ""date to Date
like in
NSSortDescriptor *sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"date" ascending:YES];
change to
NSSortDescriptor *sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"Date" ascending:YES];
and it works perfectly

displaying in a UITableView CoreData objects ordered in a Set

I have difficulties displaying objects coming from CoreData in a tableView.
I have 2 sorts of entities : Sample and SampleList. What is important to know is that a SampleList has an attribute sampleSet which is a set of samples (entity of Sample)
First I succeeded in displaying every SampleList. Here is viewDidLoad:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"SampleList" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastSampleDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle error
}
[self setSampleListArray:mutableFetchResults];
[mutableFetchResults release];
[request release];
Once I click on a row in my tableView, I would like to display in another UITableView every sample from the SampleList selected.
I thought that I could pass to the subview SampleList mySampleList. But then, I don't know what to do with it as it is not organized.
How can I return an ordered array of Sample (ordered by dateSample attribute for example) ?
Thank you for your time !
You can just use NSSet and NSArray methods on sampleSet to get an ordered array:
sortedArray = [[sampleSet allObjects] sortedArrayUsingSelector:#selector(compare:)];
or if you want to specify particular sort descriptors instead of the regular "compare" method:
sortedArray = [[sampleSet allObjects] sortedArrayUsingDescriptors:sortDescriptors];

Objective-C: [sectionInfo name] of NSFetchedResultsSectionInfo needs to be dateFormatted

I have the following code:
-(NSString *)tableView:(UITableView *)table titleForHeaderInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *sectionName = [sectionInfo name];
NSLog(#"sectionName %#", sectionName);
NSString *convDate = [dateFormatter stringFromDate: (NSDate *)sectionName];
NSLog(#"convDate %#", convDate);
return [NSString stringWithFormat:#"%#", [sectionInfo name]];
}
I am basically needing to convert the titleforheaderinsection which is a string date like "2009-12-04 00:00:00 +1100" to a nicer looking shorter string. So I have tried converting it using something like dateFormatter setDateStyle, but when i output the NSLog to console i get the following:
2009-12-22 09:42:10.156 app[94614:207] sectionName 2009-12-04 00:00:00 +1100
2009-12-22 09:42:10.157 app[94614:207] convDate (null
Obviously the convDate is not getting anything, but [sectionInfo name] should be a string. I have parsed it into its own NSString variable, so why cant i implement the dateFormatter on it?
A bit more information: I parse the date amongst other things earlier on, with the code snippet being:
if ([currentElement isEqualToString: #"date"]) {
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init] ;
[dateFormatter setDateFormat:#"eee, dd MMM yyyy"];
NSDate *convDate = [dateFormatter dateFromString:string];
if (self.isComment){
[currentComment setDate: convDate];
}else if (self.isPost)
NSLog(#"convDate is %#", convDate);
[currentPost setDate: convDate];
Now, when I debug this, essentially the raw string is "Sat, 27 Nov 2009 17:16:00 -800" but when i look at the convDate it comes out to be "2009-11-27 00:00:00 +1100". Not sure why, but in any case, thats what gets stored. I would have thought it would match the style i mentioned, so if i change the dateFormatter format to any other type, it would stuff up and convDate become nil.
Looking back at my postController: I have some snippets of interest:
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Post" inManagedObjectContext: ApplicationController.sharedInstance.managedObjectContext]];
NSArray *sortDescriptors = nil;
NSString *sectionNameKeyPath = #"date";
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(PostSite.name like '%#')", self.site.name]];
[fetchRequest setPredicate:pred];
sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc]
initWithKey:#"date" ascending:NO] ];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:
ApplicationController.sharedInstance.managedObjectContext
sectionNameKeyPath:sectionNameKeyPath cacheName:#"PostCache"];
}
return fetchedResultsController;
}
I am hoping to sort by date, and up in my code, in titleForHeaderInSection, format my string date to look more presentable.
Thanks guys
The reason you were getting unexpected behaviour is because during parsing you were setting the date format to
[dateFormatter setDateFormat:#"eee, dd MMM yyyy"];
which has no time information, which is why there was a time difference in the dates.
Also, during parsing you were setting convDate with
NSDate *convDate = [dateFormatter dateFromString:string];
which is storing an NSDate and crucially NSFetchResultsController is calling the description selector on convDate because it is not an NSString.
I'm not entirely sure why NSDateFormatter could not recognise the ISO date format.
The reason your code does not work is because
[sectionInfo name]
returns an NSString object, not an NSDate object, which is required by
[dateFormatter stringFromDate:];
You cannot simply cast an NSString to an NSDate.
Instead,
- (NSString *)tableView:(UITableView *)table titleForHeaderInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
NSString *sectionName = [sectionInfo name];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *convDate = [dateFormatter stringFromDate:[dateFormatter dateFromString:sectionName]];
[dateFormatter release];
return convDate;
}
Also, don't autorelease an object unless there is a specific reason to do so.
I found the solution by going to http://iosdevelopertips.com/cocoa/date-formatters-examples-take-2.html and using http://unicode.org/reports/tr35/#Date_Format_Patterns as a guide, I debugged my code until i ensured that the variable is matched with the incoming string