I have an NSMutableArray that contains 2 types of Objects.
Both objects contain a field for dates (date Strings with different formats) with different names.
What's the best and fastest way to sort them all based on the date? Is it possible to use an NSSortDescriptor
in this situation?
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. So that handles the simple case, but what about if you want to sort your custom objects.
The primary difference between NSArray and NSMutableArray is that a mutable array can be changed/modified after it has been allocated and initialized, whereas an immutable array, NSArray , cannot.
For just sorting array of strings: sorted = [array sortedArrayUsingSelector:@selector(compare:)]; For sorting objects with key "name": NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(compare:)]; sorted = [array sortedArrayUsingDescriptors:@[sort]];
The NSMutableArray class declares the programmatic interface to objects that manage a modifiable array of objects. This class adds insertion and deletion operations to the basic array-handling behavior inherited from NSArray . NSMutableArray is “toll-free bridged” with its Core Foundation counterpart, CFMutableArray .
If you are targeting Mac OS X v10.6 or iOS4 and higher you can sort using comparator similar to this
NSDateFormatter *formatter1 = ...; //create and configure date formatter for Class1
NSDateFormatter *formatter2 = ...; //create and configure date formatter for Class2
[arrayOfObjects sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDate *date1 = nil, *date2 = nil;
//Get first objects date
if([obj1 isKindOfClass:[Class1 class]])
{
date1 = [formatter1 dateFromString:[obj1 class1Date]];
}
else if([obj1 isKindOfClass:[Class2 class]])
{
date1 = [formatter2 dateFromString:[obj1 class2Date]];
}
//Get second objects date
if([obj2 isKindOfClass:[Class1 class]])
{
date2 = [formatter1 dateFromString:[obj2 class1Date]];
}
else if([obj2 isKindOfClass:[Class2 class]])
{
date2 = [formatter2 dateFromString:[obj2 class2Date]];
}
NSAssert(date1 != nil, @"Could not parse date from %@", obj1);
NSAssert(date2 != nil, @"Could not parse date from %@", obj2);
return [date1 compare:date2];
}];
Besides checking for the class you could also check if it responds to selector.
You could add a category to unify the date field name. Let's say class A's instances have a field "dateString" and class B's instances have a field "creationDateString"... You could do this:
@implementation A (SortByDate)
-(NSDate*)sortDate
{
static NSDateFormatter * formatter = nil ;
static dispatch_once_t once = 0 ;
dispatch_once( & once, ^{ formatter = ... } ) ;
return [ formatter dateFromString:self.dateString ] ;
}
@end
@implementation B (SortByDate)
-(NSDate*)sortDate
{
static NSDateFormatter * formatter = nil ;
static dispatch_once_t once = 0 ;
dispatch_once( & once, ^{ formatter = ... } ) ;
return [ formatter dateFromString:self.creationDateString ] ;
}
@end
Now you can sort all objects in your array by their sortDate
property:
NSArray * sortedByDateArray = [ unsortedArray sortedArrayUsingComparator:^( id a, id b ){
return [ [ a sortDate ] compare:[ b sortDate ] ] ;
}];
EDIT Or with a sort descriptor:
NSArray * sortedArray = [ unsortedArray sortedArrayUsingDescriptors:[ NSArray arrayWithObject:[ NSSortDescriptor sortDescriptorWithKey:@"sortDate" ascending:YES ] ] ] ;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With