Sort NSFetchedResultsController result based on array?

2 Solutions Collect From Internet About “Sort NSFetchedResultsController result based on array?”

I think that is not possible. Sorting the results of a fetch request (for a SQLite-based store) is done on the SQLite level, and can use only persistent attributes stored in the database. The sort descriptor cannot use Objective-C functions or variables.

So either

  • you add an additional attribute to your entity that describes the intended ordering (if that is possible), or
  • you sort the results according to your needs after fetching them (which means that you cannot use a fetched results controller for automatic change tracking anymore). Perhaps you can use the method described here: https://stackoverflow.com/a/15618277/1187415.

The above answer is not exactly true. You can do what you want, but it’s a bit complicated.

  1. Create a category on NSNumber (userID is a number, right?)
  2. Put a + global variable of NSArray type onto category using objc_setAssoc….

    @interface NSNumber(MyExtension)
    
    + (NSArray *) orderingArray;
    + (void) setOrderingArray: (NSArray *)array;
    
    - (NSComparisonResult) myOwnCompareMethodUsingArray:(NSNumber *)theOtherNumber;
    
    @end
    
    int keyVar = 0;
    
    @implementation NSNumber(MyExtension)
    
    + (NSArray *) orderingArray
    {
     return objc_getAssociatedObject(self, &keyVal);
    }
    + (void) setOrderingArray: (NSArray *)array
    {
        objc_setAssociatedObject(self, &keyVal, array, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (NSComparisonResult) myOwnCompareMethodUsingArray:(NSNumber *)theOtherNumber;
    {
     NSArray *a = [self.class orderingArray];
     if(!a) return NSOrderedSame;
     return [@([a indexOfObject:self]) compare: @([a indexOfObject:theOtherNumber])];
    } 
    
  3. Set the array somewhere:

    [NSNumber setOrderingArray:myArrayWithKeys]; 
    
  4. Use sort descriptor of type:

    [NSSortDescriptor sortDescriptorWithKey:@"userId" ascending:YES selector @selector(myOwnCompareMethodUsingArray:)]
    

This will apparently work as it works for strings with localizedCaseInsensitiveCompare:
However, it will degrade performance of the query if it is big enough and override any fetchLimit/fetchOffset optimizations. Remember that the field you are operationg on has to be unique, otherwise it will all go to hell.