Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data: What should I use as a Sort Descriptor with ordered set (ios5) in a many to many relationship

enter image description here- I have an Item Entity and a Tag Entity. - Items can have multiple Tags and Tags can be linked to multiple Items (many to many relationship). - The relationship is an "Ordered Relationship" (using Ordered relationship in IOS5) both ways.

I want to fetch all child tags for a given item

Im using the following fetch request:

NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Item"];

// Fetch all items that have a given tag
Tag* myTag = ....;
request.predicate = [NSPredicate predicateWithFormat:@"ANY tag == %@", myTag];

// This is my attempt to get the correct sort ordering (it crashes)
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"tag"
                                                                 ascending:YES];
request.sortDescriptors = @[sortDescriptor];

The above sort descriptor returns data (which I assume is in some order) but then crashes:

[_NSFaultingMutableOrderedSet compare:]: unrecognized selector sent to instance 0x10b058f0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 
'-[_NSFaultingMutableOrderedSet compare:]: unrecognised selector sent to instance 0x10b058f0'

If I give an empty sort descriptors array then I dont get a crash but the result is not ordered.

How do I correctly implement the sort descriptor in a many to many relationship using the ordered relationship feature in ios5?

like image 351
Ash Avatar asked Sep 06 '12 16:09

Ash


1 Answers

I think you may be misapprehending what an ordered relationship means in Core Data. As per this question, "ordered" doesn't mean "with regards to some property" - instead, "ordered" means "preserves the user's order" (or another specific order that would otherwise seem arbitrary). Some examples:

  • An ordered relationship would be good for steps in a recipe (the example from Apple's Core Data Release Notes) - the steps couldn't necessarily be ordered with respect to any of their properties (e.g. their text), and would have to maintain an "index" or "order" property on their own if Core Data didn't do the ordering.
  • An ordered relationship would not be good for a list of names - the user could choose to sort by first or last names, for example, and the collection of names has no real intrinsic ordering internally. The only thing that matters is display order - the data itself doesn't need to maintain that order. (The rule of thumb in Apple's docs is that if a user could conceivably choose between sort specifiers, the relationship shouldn't be ordered in Core Data.)

In your case, you try to apply a sort descriptor to the set of ordered sets (the values for the tags property) that you're fetching. This is the cause of your crash - the NSOrderedSet subclass (_NSFaultingMutableOrderedSet, in your case) doesn't implement the -compare: method that the sort descriptor would use to sort them, and so you get that exception.

I think a good solution for you would be to not use a sort descriptor at all; instead, if you want to change the preserved ordering for display to the user, get the NSOrderedSet value for tags on some Item, then get an array out of it with your own sort using -sortedArrayUsingComparator:. This will keep the data in the right order in Core Data but let you reorder it yourself programmatically.

At a higher level, you may also want to consider whether or not you really need order in your relationships. It incurs a significant performance penalty, and all you really get back is the original order in which tags were added to items (or vice versa). If you intend to change that order every time you display the tags, then you're taking that performance hit for no real benefit - make your relationships unordered, then either continue sorting programmatically or use a sort descriptor on an aggregate key, such as tags.@count, as suggested in the comments.

like image 111
Tim Avatar answered Oct 09 '22 16:10

Tim