12

In fetchedResultsController while setting the NSSortDescriptor iam getting this error unsupported NSSortDescriptor (comparator blocks are not supported).

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
                               entityForName:@"Alarm" inManagedObjectContext: managedObjectContext];
[fetchRequest setEntity:entity];

//Below code is not working and causing error. sorting use the hours&seconds part of the time attribute  

NSSortDescriptor *sort = [[NSSortDescriptor alloc]
                          initWithKey:@"time" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {

                                  NSCalendar *calendar = [NSCalendar currentCalendar];
                                  NSDateComponents *components1 = [calendar components:(NSHourCalendarUnit|NSMinuteCalendarUnit) fromDate:obj1];
                                  NSDateComponents *components2 = [calendar components:(NSHourCalendarUnit|NSMinuteCalendarUnit) fromDate:obj2];
                                  NSDate *date1 = [calendar dateFromComponents:components1];
                                  NSDate *date2 = [calendar dateFromComponents:components2];


                                  return [date1 compare:date2];

                          }];
Anil Varghese
  • 42,757
  • 9
  • 93
  • 110

2 Answers2

13

You can't use sort descriptors with comparator blocks everywhere - for instance not with Core Data fetches.

They work fine when you filter normal arrays, though.

Apart from that - was there a question in there that I overlooked?

Monolo
  • 18,205
  • 17
  • 69
  • 103
  • 1
    What I can do for getting the above result? – Anil Varghese Feb 18 '13 at 14:37
  • 1
    @Anil Well, a simple way could be to extract all your data into an array, then sort that array with the sort descriptor from your code. – Monolo Feb 18 '13 at 14:42
  • 3
    I did like that. Sorting externally after fetching. But the problem i s am using `controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath` for updating the table view. While performing deletion some other row at indexpath is getting deleted. – Anil Varghese Feb 18 '13 at 14:53
  • 4
    I think perhaps the overlooked part is _why_ the nonsensical decision (on Apple's part) to not allow comparator blocks to work with Core Data fetches in the first place. And also _how_ to work around it within Core Data fetches. – aroth Oct 15 '15 at 09:55
8

As Monolo said, you can't use comparators block with Core Data. However, you can use:

[NSSortDescriptor sortDescriptorWithKey:(NSString *) ascending:(BOOL) selector:(SEL)]

You'll need to extend your model, if you aren't using a standard selector.

For example, I just needed to order strings "a la Finder" (i.e. 1,2,9,10, and not 1,10,2,9) and I used

request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:myEntity ascending:NO selector:@selector(localizedStandardCompare:)]];

Take a look to the NSSortDescriptor Class Reference by Apple

Happy coding :)

Bruno Belotti
  • 2,414
  • 1
  • 31
  • 28
  • it does not work in Core Data. The sorting happens in the SQLite backend. localizedStandardCompare works, probably because it is a selector of NSString and apple did something to translate how it compares. – Zitao Xiong Jul 02 '15 at 21:55
  • Sorry, I don't understand your comment: I started my answer with "you can't use comparators block with Core Data", I guess it's pretty obvious that it doesn't work in Core Data... – Bruno Belotti Jul 02 '15 at 23:16
  • 2
    I mean the selector does not work on core data either. like if we have a `@selector(fancyCompare:)` on model. It does not work with Core Data. – Zitao Xiong Jul 04 '15 at 07:19
  • I don't know about other selectors, but I can assure you @selector(localizedStandardCompare:) it does work: I'm using it in a TableViewController, applying it to a NSFetchRequest, as showed in my answer (in iOS7 and iOS8, at least). – Bruno Belotti Jul 04 '15 at 21:08
  • yes, I implemented my own - (NSComparisonResult)typeCompare:(NSString*)obj2 but I get unsupported NSSortDescriptor selector: typeCompare: in core data – Zsolt Jul 22 '15 at 08:11
  • 2
    Digging up this zombie since I found the comments unhelpful- you have to use one of the built in comparator selectors. See http://stackoverflow.com/a/27972020/2200576. – spongessuck Jun 23 '16 at 13:11
  • 1
    +1 — was looking into blocks to fix the `[1, 10, 2]` sorting issue. `localizedStandardCompare:` works instead! – pkamb Jul 22 '16 at 02:03
  • I extended the model with the @objc func localizedStandardCompare(_ string: String) -> ComparisonResultfunction but it is not called. I found information that it should be an extension of the value type. In my case it is NSString. So I did this for an NSString with the function name `customCompare`, it was called but crashed with the error "unsupported NSSortDescriptor selector: customCompare:". So it doesn't work the same way as comparator. – Nikaaner May 21 '23 at 13:40