Function in a Sort Descriptor - objective-c

In my core data model, I have a person entity with properties of firstName and lastName. When I use sort descriptors with a fetchedResultsController, I sort by firstName. But if the firstName is nil, I want to use the lastName instead.
I also have a relationship between person and objects, called personOfObjects where person<-->>objects. I am sorting to present in a UITableView. It works fine except for the cases where the first name is nil. In that case they all get grouped into the same group, when these special cases should really be sorted by the last name instead.
Here is what I do now:
NSEntityDescription * entity = [NSEntityDescription entityForName:#"object" inManagedObjectContext:dataInterface.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *personSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"personOfObject.firstName" ascending:YES];
NSSortDescriptor *objectSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"objectDescription" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:personSortDescriptor, objectSortDescriptor, nil];
I thought I could create a helper function in the person class, like this:
- (NSString *) firstLast {
if (![self.firstName isNullString] ) return self.firstName;
if (![self.lastName isNullString] ) return self.lastName;
return #"";
}
and then change the first sort descriptor to refer to this function:
NSSortDescriptor *personSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"personOfObject.firstLast" ascending:YES];
NSSortDescriptor *objectSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"objectDescription" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:personSortDescriptor, objectSortDescriptor, nil];
I didn't really expect this to work (and it didn't), but I am wondering if there is a straightforward way to do something like this.

You can do this by using your own NSComparator ( How to use NSComparator? )
this question has some code for it, too:
How to Sort an NSMutableArray of Managed Objects through an object graph
You'll have to add your conditional compare in the comparator rather than chaining sort descriptors.

Related

How to fetch data of NSString from array of structure hold by NSMutableArray in objective c?

I have one NSMutableArray tempArray = \[NSMutableArray array\]; which contains an array of structured objects with multiple data: brand_package_id , slide_master_id etc....
I want to sort out the tempArray according to slide_master_id's.
Please see given image and help me to sort this problem.
Try using NSSortDescriptor:
NSSortDescriptor *slideDescriptor = [[NSSortDescriptor alloc]
initWithKey:#"slide_master_id" ascending:YES];
NSArray *sortDescriptors = #[slideDescriptor];
NSArray *sortedArray = [tempArray sortedArrayUsingDescriptors:sortDescriptors];

Sort descriptor not working on nsdate objects in NSArray.

An array contains NSDate objects, how to sort these using sort descriptor ? I am trying the code below:
NSSortDescriptor * dateSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"Date" ascending:YES];
NSArray * sortedArray = [allDates addObjectsFromArray:[allDates sortedArrayUsingDescriptors:#[dateSortDescriptor]]];
NSDate conforms to the compare: method and ascending is the default order
NSArray *sortedArray = [allDates sortedArrayUsingSelector:#selector(compare:)];
#Avt, answered this question I don't know why he removed it.
NSSortDescriptor * dateSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"timeIntervalSince1970" ascending:YES];
NSArray * sortedArray = [allDates addObjectsFromArray:[allDates sortedArrayUsingDescriptors:#[dateSortDescriptor]]];

Ordering an NSArray with NSDictionaries with objects

I have an array of dictionaries that contains objects like in the image below:
The problem I have is that I need to order the array by dates, for example in the first object I have a dueDate that is greater than the dueDate of the second object, then I have to swap them, so in other word I need to order the dictionaries inside the array based on the dueDate in ascending order, anyone have ideas?, I have tried with NSpredicate, with sortDescriptors but it isnt working, here is my sortDescriptors code:
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"dueDate" ascending:YES];
NSSortDescriptor *descriptor2 = [[NSSortDescriptor alloc] initWithKey:#"overDueDate" ascending:YES];
NSArray *descriptors = #[descriptor, descriptor2];
tasksResultArray = [tasksResultArray sortedArrayUsingDescriptors:descriptors];
Thanks in advance.
It can be done easier:
arrayOfDictionaries = [arrayOfDictionaries sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
// The logic for comparing dates, and returning the corresponding result
NSDate *date1 = (NSDate *) [(NSDictionary *)obj1 objectForKey:#"dueDate"];
NSDate *date2 = (NSDate *) [(NSDictionary *)obj2 objectForKey:#"dueDate"];
return [date1 compare:date2];
}];

Sort NSArray of custom objects by their NSDate properties

I am attempting to sort an NSArray that is populated with custom objects. Each object has a property startDateTime that is of type NSDate.
The following code results in an array, sortedEventArray, populated but not sorted. Am I going about this the completely wrong way or am I just missing something small?
NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"startDateTime"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:dateDescriptor];
NSArray *sortedEventArray = [nodeEventArray sortedArrayUsingDescriptors:sortDescriptors];
Are you sure that the startDateTime instance variables of the node events are non-nil?
If you don't have one already, you might add a (custom) -description method to your node event objects that does something like this:
- (NSString *)description {
return [NSString stringWithFormat:#"%# - %#",
[super description], startDateTime]];
}
Then in your sorting code log the array before and after:
NSLog(#"nodeEventArray == %#", nodeEventArray);
NSSortDescriptor *dateDescriptor = [NSSortDescriptor
sortDescriptorWithKey:#"startDateTime"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:dateDescriptor];
NSArray *sortedEventArray = [nodeEventArray
sortedArrayUsingDescriptors:sortDescriptors];
NSLog(#"sortedEventArray == %#", sortedEventArray);
If the startDateTime's are all nil, then the before and after arrays will have the same order (since the sorting operation will equate to sending all the -compare: messages to nil, which basically does nothing).
Did you try by specifying the NSDate comparator?
Eg:
NSSortDescriptor *dateDescriptor = [NSSortDescriptor
sortDescriptorWithKey:#"startDateTime"
ascending:YES
selector:#selector(compare:)];
This should enforce the usage of the correct comparator of the NSDate class.
Ok, I know this is a little late, but this is how I would do it:
NSArray *sortedEventArray = [events sortedArrayUsingComparator:^NSComparisonResult(Event *event1, Event *event2) {
return [event1.startDateTime compare:event2.startDateTime];
}];
Obviously, replace Event with the class of your custom object. The advantage of this approach is that you are protected against future refactoring. If you were to refactor and rename the startDateTime property to something else, Xcode probably would not change the string you're passing into the sort descriptor. Suddenly, your sorting code would break/do nothing.
You can achieve like this,
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"anyDateField" ascending:YES];
NSMutableArray *arr = [[array sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]]mutableCopy];
You can achieve this like this,
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:FALSE];
[self.Array sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

Sorting an NSArray by a key-value relationship that is 2 levels deep

I have an NSArray of UILocalNotification objects that I need to sort according to a key within the UILocalNotification's userInfo property, which is an NSDictionary. I know how to sort NSArrays by a value that is one level deep, e.g., a key within an array of NSDictionaries, but two levels deep I'm lost. I want to do something like this is psuedo-code:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"userInfo.personName" ascending:YES];
//the personName key within the userInfo NSDictionary property of a given UILocalNotification
NSArray *sortDescriptors = [[[NSArray alloc] initWithObjects:&sortDescriptor count:1] autorelease];
NSMutableArray *sortedArray = [[[NSMutableArray alloc] initWithArray:[[UIApplication sharedApplication] scheduledLocalNotifications]] autorelease];
[sortedArray sortUsingDescriptors:sortDescriptors];
Did you try your code? Apple's document (here) says it accepts key paths, not just keys.