NSSortDescriptor should sort NSDates - objective-c

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

Related

NSArray Sorting using NSSortDescriptor by considering Integer Value of Key [duplicate]

I'm trying to sort by date then start time. Start time is minutes from midnight. So if the start time is < 100 it will not sort properly.
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Appointments" inManagedObjectContext:[[DataManager sharedInstance] managedObjectContext]];
[fetchRequest setEntity:entity];
[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];
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:[[DataManager sharedInstance] managedObjectContext] sectionNameKeyPath:#"date" cacheName:#"List"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSLog(#"FetchedController: %#", fetchedResultsController);
return fetchedResultsController;
}
How could I make this sort integers properly?
If start_time is a string then it will be sorted alphabetically which means that aa is before b which also means that 11 is before 2.
To sort in a more human friendly way use NSString's localizedStandardCompare: as a selector.
[NSSortDescriptor sortDescriptorWithKey:#"start_time" ascending:YES selector:#selector(localizedStandardCompare:)]

Using an NSPredicate to access self.items

For various reasons (summarized at the end) I am experimenting with using an NSFetchedResultsController to return some NSManagedObjects.
Specifically, a Person has many Cars, modeled using the core data relationship cars. I want to add another method to Person to return the same cars as self.cars, but using a FRC.
I think I am making a basic error with my NSPredicate, which is designed to only find the cars where car.person == self:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Car"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"dateAdded" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"person == '%#'", self];
[fetchRequest setPredicate:predicate];
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
NSError *error;
BOOL success = [controller performFetch:&error];
No cars are being returned at all. Is my predicate incorrect?
Side Note - why not just use self.cars?
Like I say this is an experiment. I am hoping to benefit from the persistent cache of an NSFetchedResultsController.
The single quotes in the predicate are wrong, it should be
[NSPredicate predicateWithFormat:#"person == %#", self];
In the example you are fetching "Person" objects. Maybe you want to fetch "Car" objects instead?
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Car"];

NSFetchedResultsController not sorting on initial fetch

I am having a Core Data problem with NSFetchedResultsController. I have a one to many relationship between a parent and child entity. The array in the childFetchedResults.fetchedObjects property is NOT sorted by number (number is an int32 property in the model). It doesn't seem to matter if I use the MagicalRecord convenience category methods or not.
NSFetchRequest *req = [Child MR_requestAllSortedBy:#"number" ascending:YES withPredicate:[NSPredicate predicateWithFormat:#"parent = %#", self.parent]];
childFetchedResults = [[NSFetchedResultsController alloc] initWithFetchRequest:req managedObjectContext:[NSManagedObjectContext MR_defaultContext] sectionNameKeyPath:nil cacheName:nil];
childFetchedResults.delegate = self;
NSError *error;
[childFetchedResults performFetch:&error];
NSLog(#"fetched objects: %#", childFetchedResults.fetchedObjects);
However, if I sort the array of fetched objects using the exact same sort descriptor, it works fine:
NSLog(#"fetched objects: %#", [childFetchedResults.fetchedObjects sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"number" ascending:YES]]]);
I gather you can only use comparators which Core Data can pass on to the SQLite store when specifying sort descriptors for a fetch request. But I feel like that shouldn't matter in this case since sorting by a number has got to be supported by SQLite.
Anyone solved this? I feel like it's a similar issue to the one described here: NSSortDescriptor not being called.
As for MR_requestAllSortedBy, it's in MagicalRecord, here is the implementation:
+ (NSFetchRequest *) MR_requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context
{
NSFetchRequest *request = [self MR_requestAllInContext:context];
NSSortDescriptor *sortBy = [[NSSortDescriptor alloc] initWithKey:sortTerm ascending:ascending];
[request setSortDescriptors:[NSArray arrayWithObject:sortBy]];
return request;
}
So this was caused by fetching against a nested MOC with unsaved changes. Either fetching with the parent MOC or saving the nested MOC prior to executing the fetch resolves the problem. Similar to what was going on in this question: NSSortdescriptor ineffective on fetch result from NSManagedContext
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"RemainderDataBase" inManagedObjectContext:[self managedObjectContext]];
NSSortDescriptor *nameSort = [[NSSortDescriptor alloc]initWithKey:#"title" ascending:YES];
NSArray *sortDescriptor = [[NSArray alloc]initWithObjects:nameSort, nil];
fetchRequest.sortDescriptors = sortDescriptor;
NSPredicate *p1=[NSPredicate predicateWithFormat:#"startdate > %#", [NSDate date]];
[fetchRequest setPredicate:p1];
[fetchRequest setEntity:entity];
i think you are looking for the above code..

NSSortDescriptor for NSFetchRequest sorting unexpectedly

My entity has a property (sortOrder) that is of the type Decimal(NSDecimalNumber) but when I execute a fetch request using that property as a key, I get back results in a seemingly random order. If I output the value of the property I get really strange values until I get it's intValue.
Example: The first run produces this result. The first value is the raw value of the property. The second is the intValue, the actual value of the property when I created the object - or at least I thought.
85438160 10
74691424 20
Second run...
85333744 10
85339168 20
Third...
85263696 20
85269568 10
What the hell?
Fetch Request:
NSMutableArray *cats = [[NSMutableArray alloc] initWithArray:[CoreDataHelper searchObjectsInContext:#"RestaurantMenuCategory":nil:#"sortOrder":YES:NO:nil]];
Here is the searchObjectsInContext method from my CoreDataHelperClass:
+(NSMutableArray *) searchObjectsInContext: (NSString*)entityName : (NSPredicate *)predicate : (NSString*)sortKey : (BOOL)sortAscending : (BOOL)distinct : (NSString*)distinctProperty
{
RestaurantController *ctrl = [RestaurantController sharedRestaurantController];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:ctrl.managedObjectContext];
[request setEntity:entity];
if(distinct==YES){
[request setReturnsDistinctResults:YES];
}
if(distinctProperty!= nil){
[request setPropertiesToFetch :[NSArray arrayWithObjects:distinctProperty,nil]];
}
if(predicate != nil){
[request setPredicate:predicate];
}
if(sortKey != nil){
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
}
NSError *error;
NSMutableArray *mutableFetchResults = [[[ctrl.managedObjectContext executeFetchRequest:request error:&error] mutableCopy] autorelease];
[request release];
return mutableFetchResults;
}
You cannot use a %d format to print out an NSDecimalNumber.
NSDecimalNumber is an Objective-C object; %d is for printing "int"s. If you use the %d format string, it will probably print something non-useful like the address of the object; use "%#" instead.

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];