使用Core Data to-many-relationships时,这是一个长期存在的问题,根据NSSortDescriptor
的数量,使用Parent
实体上的children
很难对获取请求进行排序与Child
实体存在一对多的关系。这与NSFetchedResultsController
结合使用时特别有用。通常将排序描述符初始化为:
NSSortDescriptor *sortByNumberOfChildren = [[NSSortDescriptor alloc] initWithKey:@"children.@count" ascending:NO];
导致异常'Keypath containing KVC aggregate where there shouldn't be one; failed to handle children.@count
在 iOS 6.1 上,我通过将KVO访问者-countOf<Key>
作为属性添加到我的托管对象模型中作为整数类型发现了一个修复程序。我没有在我的NSManagedObject
子类中为此属性实现任何内容,因为所有的魔法似乎都在幕后发生。 (见https://stackoverflow.com/a/15546371/2042527)。
但是,这不适用于 iOS 6.0 。在这里,我发现将以下方法添加到NSManagedObject
子类可以解决问题:
- (NSUInteger)countOfChildren{
return [self.children count];
}
同时添加两者不修复两个SDK中的问题。相反,它打破了修复。
有没有人知道为什么会发生这种情况以及为什么两者之间存在差异,尽管iOS 6.0和iOS 6.1之间没有提及Core Data或Foundation的更改。
答案 0 :(得分:6)
我认为通过说“包含KVC聚合的Keypath不应该有一个;无法处理子项。@ count”Core Data想要告诉你它不支持这种排序描述符。这很可能是因为当支持SQLite存储收到您的获取请求时,它必须生成执行获取请求描述的SQL。 “孩子。@计数”的情况实际上比人们想象的要复杂得多。
重写-countOfChildren的“修复”并不是真正的修复。让我们假设这一问题解决了问题,然后在每个Parent上调用-countOfChilden。当您第一次访问self.children时,Core Data需要执行一个SQL查询,该查询确定(至少)子项的主键,创建NSManagedObjectIDs,NSManagedObjects并返回结果。如果这样做,那么你会看到非常糟糕的表现。
您的问题有几种解决方案。
<强> 1。将子计数存储在持久属性中
只需将一个属性(名称:cachedCountOfChildren,类型:整数64位)添加到您的父实体。在您的控制器层(不在您的模型层中)每次将子项分配给父项时,将cachedCountOfChildren增加1,并在每次从父项中删除子项时减少cachedCountOfChildren。然后在排序描述符键中使用cachedCountOfChildren。这将有很好的表现。
<强> 2。使用字典结果
将NSFetchRequest的resultType设置为NSDictionaryResultType。这将导致-executeFetchRequest:error:返回NSDictionaries而不是NSManagedObjects。带有NSDictionaryResultType的NSFetchRequest可以执行不同的操作。例如,您可以使用setPropertiesToGroupBy和NSExpression(...)。请查看WWDC会话“使用iCloud with Core Data(2012)”(从幻灯片122开始)以供参考。基本上,它们向您展示了如何构造一个返回包含具有此结构的字典的数组的请求:
(
{
countOfChildren = 1;
parentName = "hello";
},
{
countOfChildren = 134;
parentName = "dsdsd";
},
{
countOfChildren = 2;
parentName = "sdd";
}
)
正如您所看到的,您将获得未分类的结果。但是countOfChildren对这个数组进行排序可以非常有效地在内存中完成。在这种情况下,Core Data生成的SQL也非常有效,您将能够准确指定字典应包含的属性。因此结果也应该是非常高效的内存。此解决方案的优势在于您无需跟踪countOfChildren。
您必须根据自己的情况决定哪种解决方案最适合自己。