5

I have a field full of ids from a third party. The ids are numbers but written to the db as a string.

I want to sort a fetch sorted by this id on the value of the integer. So I'm adding this NSSortDescriptor to the NSFetchRequest.

NSNumberFormatter *numFormatter = [[NSNumberFormatter alloc] init];
[numFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSSortDescriptor *sortBy = [[NSSortDescriptor alloc] initWithKey:@"someId" ascending:YES comparator:^(id a, id b) {
    return [[numFormatter numberFromString:a] compare:[numFormatter numberFromString:b]];
}];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortBy]];

But I get results like the the following. These are still sorted as a string, alphabetically.

730275292
73900038
730172867
7350727
830138437
835164
837287901
8338804
930274
9324376

What am I not understanding about using this comparator block?

EDIT May 1 2012 9:20 AM EST

To test whether the comparator block is being used, I tried the following to sort based on the length of the field.

NSSortDescriptor *sortBy = [[NSSortDescriptor alloc] initWithKey:@"fbId" ascending:YES comparator:^(id a, id b) {
    if ([a length] < [b length]) {
        return NSOrderedAscending;
    } else if ([a length] > [b length]) {
        return NSOrderedDescending;
    } else {
        return NSOrderedSame;
    }
}];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortBy]];

I'm still getting results sorted by the alphabetically order! So this makes me think the comparator block is not even being used.

716164250
726354466
73900038
739600038
7450727
810138437
801164
801375346
8213997
Jinyoung Kim
  • 2,171
  • 20
  • 32

2 Answers2

13

Try this !

[NSSortDescriptor sortDescriptorWithKey:@"name"
ascending:YES
selector:@selector(localizedStandardCompare:)]
maxday
  • 1,322
  • 1
  • 16
  • 32
1

I don't use NSFetchRequest so I can't comment on that specifically, but it appears to be something related to it. The code you use in your comparator block is just fine. I setup an array of the exact numbers you show and then sorted them using your code and everything worked out fine:

    NSArray *array = [NSArray arrayWithObjects:@"730275292",
                      @"73900038",
                      @"730172867",
                      @"7350727",
                      @"830138437",
                      @"835164",
                      @"837287901",
                      @"8338804",
                      @"930274",
                      @"9324376", nil];
    NSNumberFormatter *numFormatter = [[NSNumberFormatter alloc] init];
    [numFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
    NSArray *sArray = [array sortedArrayUsingComparator:^(id a, id b) {
        return [[numFormatter numberFromString:a] compare:[numFormatter numberFromString:b]];
    }];
    NSLog(@"%@",sArray);

When the above code runs, I get a log of:

(
    835164,
    930274,
    7350727,
    8338804,
    9324376,
    73900038,
    730172867,
    730275292,
    830138437,
    837287901
)

I believe this is the order you're looking for. You might consider taking the results of your fetch request and sorting them in an array after you've received them. I doubt it matters whether an array does the sorting or the fetch request does the sorting. Most likely there's no performance gain of using one over the other.

If you still want NSFetchRequest to do the sorting, then there might be something your missing in order to get it to sort properly. Honestly, I'm not sure since I've not used it.

UPDATE

Quickly looking through the NSFetchRequest docs, I've found that there are some parameters that affect sorting. For example, in the docs for the resultType it gives this message:

You use setResultType: to set the instance type of objects returned from executing the request—for possible values, see “NSFetchRequestResultType.” If you set the value to NSManagedObjectIDResultType, this will demote any sort orderings to “best efforts” hints if you do not include the property values in the request.

So it looks as though the return type might be affecting your sorting.

Aaron Hayman
  • 8,492
  • 2
  • 36
  • 63
  • 1
    The top answer to http://stackoverflow.com/questions/4789782/nsfetchedresultscontroller-custom-sort-not-getting-called suggests that some objective-c comparator blocks cannot be "compiled" into SQL and suggested basically what you're suggesting. Ehh, reasonable workaround, but I would love to get at the real answer of why the comparator block isn't working. Also, often this isn't a solution as it might be important to have the data in an NSFetchResultsController (e.g. when you're using it in a TableView and taking advantage of NSFetchedResultsControllerDelegate for updates to the UI). – Jinyoung Kim May 01 '12 at 13:57
  • Well, I just update the answer. I did a search on 'sort' in the NSFetchRequest and found that `resultType` can affect sorting. You might want to look into that. Unfortunately, I use SQLite directly, instead of using Core Data, so this is about the extent of my knowledge. – Aaron Hayman May 01 '12 at 14:02
  • 1
    The real answer is exactly what you noted-- fetch requests can't convert comparator blocks into SQL, so sort descriptors that rely on those blocks don't work with Core Data fetch requests. The documentation link in that answer explains it in more detail. – Tom Harrington May 01 '12 at 20:25