Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I sort an NSMutableArray with custom objects in it?

What I want to do seems pretty simple, but I can't find any answers on the web. I have an NSMutableArray of objects, and let's say they are 'Person' objects. I want to sort the NSMutableArray by Person.birthDate which is an NSDate.

I think it has something to do with this method:

NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(???)]; 

In Java I would make my object implement Comparable, or use Collections.sort with an inline custom comparator...how on earth do you do this in Objective-C?

like image 549
rustyshelf Avatar asked Apr 30 '09 06:04

rustyshelf


People also ask

How do you sort an array of objects in Objective C?

The trick to sorting an array is a method on the array itself called "sortedArrayUsingDescriptors:". The method takes an array of NSSortDescriptor objects. These descriptors allow you to describe how your data should be sorted.

Can we sort array of objects?

To sort an array of objects, you use the sort() method and provide a comparison function that determines the order of objects.


2 Answers

Compare method

Either you implement a compare-method for your object:

- (NSComparisonResult)compare:(Person *)otherObject {     return [self.birthDate compare:otherObject.birthDate]; }  NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)]; 

NSSortDescriptor (better)

or usually even better:

NSSortDescriptor *sortDescriptor; sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"                                            ascending:YES]; NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]]; 

You can easily sort by multiple keys by adding more than one to the array. Using custom comparator-methods is possible as well. Have a look at the documentation.

Blocks (shiny!)

There's also the possibility of sorting with a block since Mac OS X 10.6 and iOS 4:

NSArray *sortedArray; sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(Person *a, Person *b) {     return [a.birthDate compare:b.birthDate]; }]; 

Performance

The -compare: and block-based methods will be quite a bit faster, in general, than using NSSortDescriptor as the latter relies on KVC. The primary advantage of the NSSortDescriptor method is that it provides a way to define your sort order using data, rather than code, which makes it easy to e.g. set things up so users can sort an NSTableView by clicking on the header row.

like image 58
17 revs, 10 users 72% Avatar answered Sep 25 '22 23:09

17 revs, 10 users 72%


See the NSMutableArray method sortUsingFunction:context:

You will need to set up a compare function which takes two objects (of type Person, since you are comparing two Person objects) and a context parameter.

The two objects are just instances of Person. The third object is a string, e.g. @"birthDate".

This function returns an NSComparisonResult: It returns NSOrderedAscending if PersonA.birthDate < PersonB.birthDate. It will return NSOrderedDescending if PersonA.birthDate > PersonB.birthDate. Finally, it will return NSOrderedSame if PersonA.birthDate == PersonB.birthDate.

This is rough pseudocode; you will need to flesh out what it means for one date to be "less", "more" or "equal" to another date (such as comparing seconds-since-epoch etc.):

NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {   if ([firstPerson birthDate] < [secondPerson birthDate])     return NSOrderedAscending;   else if ([firstPerson birthDate] > [secondPerson birthDate])     return NSOrderedDescending;   else      return NSOrderedSame; } 

If you want something more compact, you can use ternary operators:

NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {   return ([firstPerson birthDate] < [secondPerson birthDate]) ? NSOrderedAscending : ([firstPerson birthDate] > [secondPerson birthDate]) ? NSOrderedDescending : NSOrderedSame; } 

Inlining could perhaps speed this up a little, if you do this a lot.

like image 24
Alex Reynolds Avatar answered Sep 22 '22 23:09

Alex Reynolds