Stian Høiland
Stian Høiland

Reputation: 3664

NSSortDescriptor with arbitrary sorting

I can't wrap my head around how to do arbitrary sorting with a NSSortDescriptor.

I want to do something like this:

NSArray *sortAlgorithm = [NSArray arrayWithObjects:@"@", @"#", @"!", @"&", @"r", @"a", nil];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" 
                                                               ascending:YES 
                                                              comparator:
    ^(id obj1, id obj2) {
        NSComparisonResult comparisonResult;
        //Some code that uses sortAlgorithm.
        return comparisonResult;
    }
];

This would sort the objects by the key name so that any key that starts with @, e.g. @home, would come before any key that starts with r, e.g. radical, and that again would come before any key that starts with a, e.g. anything.

The above is just an example. The point is to enable completely arbitrary sorting.

This is to be used for a NSFetchedResultsController.

What would the code for //Some code that uses sortAlgorithm look like?

EDIT:

Code surrounding my attempt to implement a sortDescriptor, as pr. occulus' suggestion:

- (NSFetchedResultsController *)fetchedResultsController {
    if (__fetchedResultsController)
        return __fetchedResultsController;

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    fetchRequest.entity = [NSEntityDescription entityForName:@"Tag" inManagedObjectContext:self.temporaryManagedObjectContext];

    //NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO comparator:^(id obj1, id obj2) {

        NSArray *sortAlgorithm = [NSArray arrayWithObjects:@"#", @"!", @"@", @".", nil];

        NSString *obj1FirstChar = [(NSString *)obj1 substringToIndex:1];
        NSString *obj2FirstChar = [(NSString *)obj2 substringToIndex:1];
        int idx1 = [sortAlgorithm indexOfObject:obj1FirstChar];
        int idx2 = [sortAlgorithm indexOfObject:obj2FirstChar];

        if ( idx1 < idx2 )
            return NSOrderedAscending;
        else if ( idx1 > idx2 )
            return NSOrderedDescending;
        else
            return NSOrderedSame;
    }];

    fetchRequest.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
    fetchRequest.fetchBatchSize = 20;        

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.temporaryManagedObjectContext sectionNameKeyPath:nil cacheName:@"Tags"];

    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    [self.fetchedResultsController performFetch:nil];

    return __fetchedResultsController;
}

The commented-out sortDescriptor works.

There is definitely a property called name on objects of entity "Tag". But even if there weren't, that doesn't seem to be the problem. Xcode doesn't seem to even be compiling that line of code (the sortDescriptor), which sounds ridiculous. Breakpoints are working just fine, but aren't breaking on that specific line of code.

Upvotes: 4

Views: 3209

Answers (1)

occulus
occulus

Reputation: 17014

You need to pull out the first characters of obj1 and obj2 strings as NSStrings, find their indexes in your arbitrary ordering array, then compare the positions.

Something like this: (put this code in your ^ block)

NSString *obj1FirstChar = [(NSString *)obj1 substringToIndex:1];
NSString *obj2FirstChar = [(NSString *)obj2 substringToIndex:1];
int idx1 = [sortAlgorithm indexOfObject:obj1FirstChar];
int idx2 = [sortAlgorithm indexOfObject:obj2FirstChar];

// NOTE: we haven't dealt with the case where one of the
// chars wasn't found in the array of characters. A strategy
// for this would need to be decided.

if (idx1 == idx2) {
    return NSOrderedSame;
}
if (idx1 < idx2) {
    return NSOrderedAscending;
}
return NSOrderedDescending;

Not tested, may require a little tweaking. Watch out for upper/lower case character differences.

UPDATE: It seems there are problems with using custom sort descriptors and SQL backed core data stores. Please see this question for more info.

Upvotes: 3

Related Questions