Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting core data position changes with sort descriptors for iPhone

I have a CoreData entity with two attributes. One called 'position' the other called 'positionChange'. Both of them are integers where the position attribute is the current position and the positionChange is the difference between the previous position and the new position. This means that the positionChange can be negative.

Now I would like to sort by positionChange. But I would like it to disregard the negative values. Currently I'm sorting it descending, which will give the result: 2, 1, 0, -1, -2. But what I'm looking for is to get this result: 2, -2, 1, -1, 0.

Any ideas on how to solve this using sort descriptors?


EDIT

I got 2 classes, one called DataManager and the other containing my NSNumber category (positionChange is of type NSNumber).

In DataManager I have a method called 'fetchData:' where I'm executing my fetch request with a sort descriptor:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Entity" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"positionChange" ascending:NO selector:@selector(comparePositionChange:)];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

I'm doing some more stuff to the request, but that's not interesting for this issue.

My NSNumber category should be exactly like the one you posted: In the .h:

@interface NSNumber (AbsoluteValueSort)
- (NSComparisonResult)comparePositionChange:(NSNumber *)otherNumber;
@end

And in the .m:

@implementation NSNumber (AbsoluteValueSort)

- (NSComparisonResult)comparePositionChange:(NSNumber *)otherNumber
{
    return [[NSNumber numberWithFloat:fabs([self floatValue])] compare:[NSNumber numberWithFloat:fabs([otherNumber floatValue])]];
}

@end

When I call fetchData on my DataManager object I get this error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'unsupported NSSortDescriptor selector: comparePositionChange:'

Any ideas of what might be the case? I have included my NSNumber category header file in my DataManager class.

like image 847
Anonymous Avatar asked Jun 30 '11 13:06

Anonymous


2 Answers

The reason that code fails with the unsupported NSSortDescriptor selector error is that you're using a SQLite data store and attempting to use a Cocoa method as the sort descriptor. With a SQLite store, sort descriptors are translated on the fly into SQL and sorting is done by SQLite. That really helps performance but it also means that sorting is done in a non-Cocoa environment where your custom comparison method doesn't exist. Sorting like this only works for common, known methods and not for arbitrary Cocoa code.

A simple fix would be to do the fetch without sorting, get the results array, and sort that. Arrays can be sorted using whatever Cocoa methods you want, so med200's category should be useful there.

You could also change from a SQLite data store to a binary store, if your data set isn't very large.

like image 83
Tom Harrington Avatar answered Nov 14 '22 02:11

Tom Harrington


Try this, assuming your positionChange is an NSNumber:

@interface NSNumber (AbsoluteValueSort)

-(NSComparisonResult) comparePositionChange:(NSNumber *)otherNumber;

@end

followed by:

@implementation NSNumber (AbsoluteValueSort)

-(NSComparisonResult) comparePositionChange:(NSNumber *)otherNumber
{
    return [[NSNumber numberWithFloat: fabs([self floatValue])] compare:[NSNumber numberWithFloat: fabs([otherNumber floatValue])]];
}

@end

and then do this:

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"positionChange" ascending:NO selector:@selector(comparePositionChange:)];

and sort with that descriptor. If you want to make it so that -2 is always after 2, or 5 is always after -5 you can modify comparePositionChange: to return NSOrderedAscending in the cases when one number is the negative of the other.

like image 2
med200 Avatar answered Nov 14 '22 03:11

med200