Anders
Anders

Reputation: 2941

Sort NSFetchedResultsController result based on array?

I would like to construct a NSPredicate or NSSortDescriptor (Core Data search) that is based on the content of an array.

The array will consists of userId:s in the right order:

[1, 2, 5, 3];

I would like to present the result for my NSFetchedResultsController in the same order.

So I will:

  1. Get the right users (I have done this)
  2. Sort the list of users based on my sorted array with userIds.

Is this possible to do, and how can I do it?

Upvotes: 3

Views: 611

Answers (2)

Terminus
Terminus

Reputation: 949

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.

Upvotes: 0

Martin R
Martin R

Reputation: 539685

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.

Upvotes: 3

Related Questions