Very custom order using NSSortDescriptor
Asked Answered
L

2

5

Let's say I have objects with different statuses. Statuses are from 0 to 2. I need to sort them using NSSortDescriptor in this way:

1

2

0

Any suggestions?

Lafferty answered 24/8, 2011 at 15:54 Comment(0)
R
7

Something like this (untested):

descriptor = [[[NSSortDescriptor alloc]
          initWithKey:@"status"
          ascending:YES
          selector:@selector(customStatusCompare:)] autorelease];

@interface NSNumber (CustomStatusCompare)
- (NSComparisonResult)customStatusCompare:(NSNumber*)other;
@end

@implementation NSNumber (CustomStatusCompare)
- (NSComparisonResult)customStatusCompare:(NSNumber*)other {
  NSAssert([other isKindOfClass:[NSNumber class]], @"Must be a number");
  if ([self isEqual:other]) {
    return NSOrderedSame;
  }
  else if (... all your custom comparison logic here ...)
  }
}
Resuscitate answered 24/8, 2011 at 16:2 Comment(8)
Thank you, it's ok, but could you also help with this "all your custom comparison logic here". I'm a newbie...Lafferty
It's an NSNumber, so you'll want the integerValue to get to a simple integer. Compare them with <, = and > and return NSOrderedDescending, NSOrderedSame, or NSOrderedAscending based on how you want them to be ordered. In your case, if [self integerValue] is 1, then it's always NSOrderedAscending (since we already checked for equality). If it's 0, then it's always NSOrderedDescending. If it's 2, then you need to check the other value to figure out which to return.Resuscitate
Can't get descriptor to call (customStatusCompare:) in category.Lafferty
What error are you seeing? Are you sure you're compiling the .m file that provides the implementation? Are you including the @interface .h into the file that references customStatusCompare:?Resuscitate
I got it working, the success depends on the order you pass the statuses. I need an independent sorter. Here is my code: - (NSComparisonResult)customStatusCompare:(NSNumber*)status { if ([self isEqual:status]) { return NSOrderedSame; } else if ([self isEqual:[NSNumber numberWithInt:1]]) { return NSOrderedAscending; } else if ([self isEqual:[NSNumber numberWithInt:2]]) { return NSOrderedSame; } else if ([self isEqual:[NSNumber numberWithInt:0]]) { return NSOrderedDescending; } return 0; } @endLafferty
Sorry, it's wrong code. Here is the right one: if ([self isEqual:status]) { return NSOrderedSame; } else if ([self isEqual:[NSNumber numberWithInt:1]]) { return NSOrderedDescending; } else if ([self isEqual:[NSNumber numberWithInt:2]]) { return NSOrderedSame; } else if ([self isEqual:[NSNumber numberWithInt:0]]) { return NSOrderedAscending; } return 0;Lafferty
That doesn't look right. if ([self isEqual:[NSNumber numberWithInt:2]]) { return NSOrderedSame; } seems wrong. You need to actually check the value of status in this case. BTW, I would also pull out the value into an int and do your work that way rather than generating so many NSNumber objects. That's fairly optimized, but this code still gets called a lot.Resuscitate
I finally got it working, tomorrow will post here the code. :) Thank you Rob for getting me understand the goal.Lafferty
A
3

Use a custom comparator or selector. NSSortDescriptor has some methods you should take a look at. From the NSSortDescriptor Class Reference:

+ sortDescriptorWithKey:ascending:selector:
– initWithKey:ascending:selector:
+ sortDescriptorWithKey:ascending:comparator:
– initWithKey:ascending:comparator:

You will likely run into problems if you're passing these kinds of sort descriptors to a Core Data fetch request, though.

Angwantibo answered 24/8, 2011 at 16:1 Comment(3)
We seem to be having these Core Data fetch request "problems". Can you elaborate as to the cause? Core Data is just throwing an exception.Taite
What do your sort descriptors look like? You can't use a custom selector or comparator with Core Data fetch requests.Angwantibo
Got it. Thanks. We were trying to use a comparator.Taite

© 2022 - 2024 — McMap. All rights reserved.