Tuesday 22 April 2014

Sort NSArray with custom objects

Every app has to work with some data and this data is usually structured in custom classes. A music app will probably have a Song class, a chat app will have a Friend class, a recipe app will have a Recipe class and so on. And sometimes you want to display a sorted list of objects. Let’s find out about the different methods to do this.


The objects in the array we’re going to sort are instances of a Person class that looks like this:


@interface Person : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *surname;
@property (nonatomic, strong) NSDate *dateOfBirth;

@end



And the array contains the following data:

Smith John 03/01/1984
Andersen Jane 16/03/1979
Clark Anne 13/09/1995
Smith David 19/07/1981
Johnson Rose 22/02/1989




Sort using NSComparator

A comparator is a block object used for comparison operations. It’s definition looks like this:
typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);

The arguments are the objects we are trying to compare. The block returns an NSComparisonResult value to denote the ordering of the two objects.

To sort the whole array you will use the method sortArrayUsingComparator: like this:



NSArray *sortedArray = [self.persons sortedArrayUsingComparator:^NSComparisonResult(Person *p1, Person *p2){

    return [p1.surname compare:p2.surname];

}];



The sorted array will look like this:
Andersen Jane
Clark Anne
Johnson Rose
Smith John
Smith David




Sort using NSDescriptor

Sort descriptors can be used not just for sorting arrays but also to specify how the elements in a table view should be arranged and also with Core Data to specify the ordering of objects returned from a fetch request. With sort descriptors you can easily sort the array by multiple keys. We’ll sort our array by surname and then by name.


NSSortDescriptor *firstDescriptor = [[NSSortDescriptor alloc] initWithKey:@"surname" ascending:YES];
NSSortDescriptor *secondDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];

NSArray *sortDescriptors = [NSArray arrayWithObjects:firstDescriptor, secondDescriptor, nil];

NSArray *sortedArray = [self.persons sortedArrayUsingDescriptors:sortDescriptors];




The resulting array will look like this:
Andersen Jane
Clark Anne
Johnson Rose
Smith David
Smith John





Sort using selectors

You can define your own method for comparing two objects and use it to sort the array. The comparator message is sent to each object in the array and has as its single argument another object in the array. The method should return NSOrederedAscending if the array is smaller than the argument, NSOrderedDescending if the array is larger than the argument and NSOrderedSame if they are equal.



- (NSComparisonResult)compare:(Person *)otherPerson 
{

    return [self.dateOfBirth compare:otherPerson.dateOfBirth];
}




This method is defined and implemented in our Person class, it sorts persons by date of birth.
All these methods do the same thing, sort an array, so you might be wondering which one to use. When you need to sort by multiple keys, the easiest way is to use sort descriptors. If you have a complicated compare method then it would make sense to have it as a selector in your class. Blocks have been introduced in iOS 4 and are a powerful tool. You can use them without a variable for a simple compare method (as presented here) or you can define a block and have a complex implementation instead of using a selector. There’s no correct answer, just use the one that makes your life easy when writing the code.














No comments:

Post a Comment