views:

13860

answers:

6

What I want to do seems pretty simple, but I can't find any answers on the web. I have an NSMutableArray of objects, let's say they are 'Person' objects. I want to sort the NSMutable array 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?

+4  A: 

Your Person objects need to implement a method, say compare: which takes another Person object, and return NSComparisonResult according to the relationship between the 2 objects.

Then you would call sortedArrayUsingSelector: with @selector(compare:) and it should be done.

There are other ways, but as far as I know there is no Cocoa-equiv of the Comparable interface. Using sortedArrayUsingSelector: is probably the most painless way to do it.

freespace
+6  A: 

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:

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;
}
Alex Reynolds
Using sortUsingFunction:context: is probably the most c-ish way and definitly the most unreadable one.
Georg
What's wrong with a "c-ish" approach? It works fine.
Alex Reynolds
There's nothing really wrong with it, but I think there are now much better alternatives.
Georg
Perhaps, but I don't think it would be any less readable to someone from a Java background who might be looking for something similar to Java's abstract Comparator class, which implements compare(Type obj1, Type obj2).
Alex Reynolds
I think the biggest stumbling block to using sortUsingFunction for some one with out a solid C background would be: a) realising it wants a function pointer; b) get used to the idea of a function pointer; c) parse the function pointer so as to construct the required function.
freespace
I get the sense a couple of you are looking for any reason whatsoever to criticize this perfectly fine answer, even if that criticism has very little technical merit. Weird.
Alex Reynolds
+38  A: 

Either you implement a compare-method for your object:

- (NSComparisonResult)compare:(id)otherObject {
    return [self.birthDate compare:otherObject];
}

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

or even better: (The default sorting selector of NSSortDescriptor is compare:)

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                              ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];
Georg
+1  A: 

there is a missing step in gs 2nd answer, works fine then.

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                              ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptor:sortDescriptors];

(I did not write in the comment because I just logged in and without reputation, I can't comment :-/)

Manuel Spuhler
The method call is actually "sortedArrayUsingDescriptors:", with an 's' at the end.
LucasTizma
Thanks, haven't seen that 's'.
Georg
+1  A: 

For some reason the topmost answer didn't work for me. I was getting a warning on compile and it crashed at runtime. Here the code I used:

NSSortDescriptor *dateSorter = [[NSSortDescriptor alloc] initWithKey:@"Date" ascending:YES];
[filteredShowsList sortUsingDescriptors:[NSArray arrayWithObject:dateSorter]];

Note that filteredShowsList has to be a NSMutableArray, not a NSArray!

Sam V
[NSArray dateSorter] is wrong, use [NSArray arrayWithObject:dateSorter]
Georg