Core data NSSortDescriptor,用于根据核心数据中的项目数对多个关系进行排序

Core data NSSortDescriptor,用于根据核心数据中的项目数对多个关系进行排序,core-data,ios6,nsfetchedresultscontroller,key-value-observing,nssortdescriptor,Core Data,Ios6,Nsfetchedresultscontroller,Key Value Observing,Nssortdescriptor,在对多个关系使用核心数据时,一个长期存在的问题是,很难使用NSSortDescriptor对父实体上的获取请求进行排序,这是基于子实体与子实体处于一对多关系的子实体的数量。这在与NSFetchedResultsController结合使用时特别有用。通常将排序描述符初始化为: NSSortDescriptor *sortByNumberOfChildren = [[NSSortDescriptor alloc] initWithKey:@"children.@count" ascending:N

在对多个关系使用核心数据时,一个长期存在的问题是,很难使用
NSSortDescriptor
父实体上的获取请求进行排序,这是基于
子实体与
子实体处于一对多关系的
子实体的数量。这在与
NSFetchedResultsController结合使用时特别有用。通常将排序描述符初始化为:

NSSortDescriptor *sortByNumberOfChildren = [[NSSortDescriptor alloc] initWithKey:@"children.@count" ascending:NO];
导致异常
“包含KVC聚合的关键路径,其中不应该有一个;无法处理子项。@count

在iOS 6.1上,我发现了一个修复方法,将KVO访问器
-countOf
作为一个整型属性添加到我的托管对象模型中。在我的
NSManagedObject
子类中,我没有为这个属性实现任何东西,因为所有的魔法似乎都发生在幕后。(见附件)

但是,这在iOS 6.0上不起作用。在这里,我发现将以下方法添加到
NSManagedObject
子类可以解决问题:

- (NSUInteger)countOfChildren{
      return [self.children count];
  }
将两者相加不会解决两个SDK中的问题。相反,它打破了固定

有没有人知道为什么会发生这样的事情,为什么两者之间存在差异,即使没有提到在IOS 6和IOS 6.1之间的核心数据或基础的改变。

< P>我认为,“KKY路径包含KVC集合,不应该有一个;没有处理孩子。”核心数据想告诉您,它不支持这种排序描述符。这很可能是因为当后台SQLite存储接收到您的获取请求时,它必须生成符合获取请求描述的SQL。“children.@count”的情况实际上比人们想象的要复杂得多

覆盖countOfChildren的“修复”并不是真正的修复。让我们先假设一下,这解决了问题,然后将对每个家长调用countOfChilden。当您首次访问self.children时,核心数据需要执行SQL查询,该查询确定(至少)子项的主键,创建NSManagedObjects、NSManagedObjects并返回结果。如果这起作用,那么您将看到非常糟糕的性能

你的问题有几种解决办法

1。将子计数存储在持久属性中

只需向父实体添加一个属性(名称:cachedCountOfChildren,类型:Integer 64位)。在控制器层(而不是模型层)中,每次将子对象指定给父对象时,将cachedCountOfChildren增加1,每次从父对象中删除子对象时,将cachedCountOfChildren减少1。然后在排序描述符键中使用cachedCountOfChildren。这将有很好的表现

2。使用字典结果

将NSFetchRequest的resultType设置为NSDictionaryResultType。这将导致-executeFetchRequest:error:返回NSDictionaries而不是NSManagedObjects。具有NSDictionaryResultType的NSFetchRequest可以执行不同的操作。例如,您可以使用setPropertiesToGroupBy和NSExpression(…)。请查看WWDC课程“使用iCloud和核心数据(2012)”(从幻灯片122开始)以供参考。基本上,它们向您展示了如何构造一个请求,该请求将返回一个数组,该数组包含具有以下结构的词典:

(
 {
  countOfChildren = 1;
  parentName = "hello";
 },
 {
  countOfChildren = 134;
  parentName = "dsdsd";
 },
 {
  countOfChildren = 2;
  parentName = "sdd";
 }
)
如您所见,您将返回未排序的结果。但按孩子数对数组进行排序可以在内存中非常有效地完成。在这种情况下,由核心数据生成的SQL也将非常有效,您将能够准确地指定字典应该包含哪些属性。因此,结果也应该是非常高效的内存。这个解决方案的优点是你不必记录孩子的数量


您必须根据自己的情况决定哪种解决方案最适合自己。

您将此添加到了
NSManagedObjectModel
?很难看出它是如何编译的,更不用说工作了。
NSManagedObjectModel
与其他类没有任何关系。对不起,我的错,我的意思是第二次也是
NSManagedObject
子类。我已经纠正了这个错误。这不是对你的确切问题的解决方案,而是对它的另一种看法:把孩子们带回来,数一数不同父母的数目如何?也许这对您有帮助。为什么不在NSManagedObject子类(即模型层)上实现它?实现什么?1或2?我想知道为什么您为1编写了以下内容:
在控制器层(而不是模型层)中,每次您…
时,将cachedCountOfChildren增加1。因为在完美的世界中,您的NSManagedObject应该非常简单。这是因为许多原因(性能、复杂性等)。在你的子类中正确地做聪明的事情是非常困难的。例如,当一个对象由于内存中的所有属性都设置为nil而变成故障时,您会收到一个针对“children”的KVO通知。并非所有属性更改都是由您或用户引起的更改。上下文可以将对象转化为错误,您可以更改子对象的计数。