NSSortDescriptor to sort by the number of items in the Master Data for Many section

The problem with using Core Data to-many relationships is very difficult to sort a query using NSSortDescriptor on a Parent object based on the number of children to-many to the Child object. This is especially useful in combination with the NSFetchedResultsController . Usually initializing a sort descriptor as:

 NSSortDescriptor *sortByNumberOfChildren = [[NSSortDescriptor alloc] initWithKey:@" children.@count " ascending:NO]; 

results in an exception 'Keypath containing KVC aggregate where there shouldn't be one; failed to handle children.@count 'Keypath containing KVC aggregate where there shouldn't be one; failed to handle children.@count

In iOS 6.1, I discovered a fix by adding KVO accessor -countOf<Key> as an attribute of my managed -countOf<Key> model as an integer type. I have not implemented anything for this attribute in my NSManagedObject subclass, as all the magic seems to happen under the hood. (see https://stackoverflow.com/a/165778/ ).

However, this does not work on iOS 6.0 . Here, I found that adding the following method to your NSManagedObject subclass fixes the problem:

 - (NSUInteger)countOfChildren{ return [self.children count]; } 

Adding both parameters does not fix the problem in both SDKs. On the contrary, he interrupts the correction.

Does anyone know why this happens and why there is a difference between them, although there is no mention of changes in Core Data or Foundation between iOS 6.0 and iOS 6.1.

+7
source share
1 answer

I think that saying "Keypath containing the KVC aggregate, where it should not be, could not handle the children. @Count" Core Data wants to tell you that it does not support this kind of sort descriptor. This is very likely because when the SQLite backup store receives your fetch request, it must generate SQL that does what the fetch request describes. The "kids. @Count" case is actually more complicated under the hood than you might think.

A fix with an override of -countOfChildren is not really a fix. Suppose for a second that this fixes the problem, then -countOfChilden will be called for each parent. When you first access self.children, Core Data should execute an SQL query that defines (at least) the primary keys of the children, creates NSManagedObjectID, NSManagedObjects and returns the result. If this works, you will see very poor performance.

There are several solutions to your problem.

1. Store the child account in a persistent attribute

Just add the attribute (name: cachedCountOfChildren, enter: Integer 64 bit) into the parent object. In your controller layer (NOT IN YOUR MODEL LAYER), increment cachedCountOfChildren by 1 each time you assign a child to the parent and decrease cachedCountOfChildren every time you remove the child from the parent. Then you use cachedCountOfChildren in your sort key handle. This will have great performance.

2. Use dictionary results

Set resultType of your NSFetchRequest to NSDictionaryResultType. This will call -executeFetchRequest: error: return NS dictionaries instead of NSManagedObjects. NSFetchRequest with NSDictionaryResultType can do different things. For example, you can use setPropertiesToGroupBy and NSExpression (...). Please look at the WWDC session β€œUsing iCloud with Master Data (2012)” (starting at slide 122) for reference. They basically show you how to build a query that will return an array containing dictionaries that have this structure:

 ( { countOfChildren = 1; parentName = "hello"; }, { countOfChildren = 134; parentName = "dsdsd"; }, { countOfChildren = 2; parentName = "sdd"; } ) 

As you can see, you will get an unsorted result. But sorting this countOfChildren array can be done in memory very efficiently. The generated SQL Core Data will also be very efficient in this case, and you can specify exactly which attributes the dictionaries should contain. Thus, the result should also be very memory efficient. The advantage of this solution is that you do not need to track countOfChildren.

You must decide which solution is best for you, depending on your situation.

+6
source

All Articles