class 与键 @sum 的键值编码不兼容

class is not key value coding-compliant for the key @sum

好的,如果必须的话,请投反对票,但我准备好通过一些事情,因为这让我发疯。我有一个 core data 应用程序 (OS X),有一对 NSTableViews(基于单元格)通过 NSArrayControllers 连接。我使用一些自定义方法设置了 Entity class'。我可以添加、删除、编辑数据以及对数据执行各种操作——一切都很好。

我决定为 运行 总和添加一个新列,并使用我看到的 @sum。无论我做什么,我都会不断收到错误消息。

我有一个实体 "Store" 和另一个实体 "Item",它们是一对多的关系。在 Item 实体中,我有一个名称和价格属性。

在主 window 上,我有两个 NSTableViewNSArrayController 控制器,一个用于商店,一个用于物品。 Item NSArrayController 的内容由 Store Controller - 所选项目控制。

我向项目 NSTableView 添加了一个新列,将其绑定到项目控制器并将其模型键路径设置为 @sum.price - 这会导致错误。

我可能遗漏了一些简单的东西,关于如何正确执行此操作有什么想法吗?

谢谢。

--[编辑]----

商店NSArrayController: - 对象控制器 - 实体名称:商店

项目NSArrayController

项目NSTableView

第一列:

第二列:

新的总和列:

我收到的错误是:"the entity Item is not key value coding-compliant for the key "@sum"."

考虑你的第一列。它绑定到项目控制器,arrangedObjectsname。每个单元格都有一个名称数组吗?没有。每个人都有一个名字。

虽然该列绑定有时表示为像 Item Controller.arrangedObjects.name 这样的关键路径,但它实际工作的方式是整个列显示 arrangedObjects,每行一个元素,但是 name 分别应用于该集合的每个元素。因此,每个单元格都有一个名称。

现在考虑您的新专栏。这些行再次对应于 Item Controller 的 arrangedObjects,但模型键路径单独应用于每个元素。但是模型键路径包含一个集合运算符 @sum,它不适用于单个元素(Item 实体)。因此错误。

您可以创建一个文本字段(在 table 之外)显示所选商店所有商品的价格总和。您可以将文本字段的值绑定绑定到项目控制器,arrangedObjects@sum.price。文本字段与 table 列的工作方式不同,因为它只显示一个内容。它确实使用了 [ItemController valueForKeyPath:@"arrangedObject.@sum.price"] 的结果。集合运算符将应用于集合。

您还可以将文本字段绑定到项目控制器,selection@sum.price 以让它显示项目的价格总和在项目table中选择了

绑定不提供任何方式来获得 运行 总和,如果我明白你的意思(第一行显示第一个项目的价格,第二行显示价格的总和第一项和第二项等)。这样的 运行 总和将取决于上下文。给定行的值将取决于前几行的值。例如,以不同方式对 table 排序将意味着给定项目旁边的 运行 总和会发生变化,因为它之前的项目集已发生变化。绑定不能这样做。他们不知道位置、索引或兄弟姐妹。


更新:

要获得 运行 总和,您需要不对列使用绑定。让您的视图或 window 控制器采用 NSTableViewDataSource(如果尚未采用)。然后将 table 视图的 dataSource 出口连接到它。

在您的数据源 class 中,实施 -tableView:objectValueForTableColumn:row:。检查列 identifier。对于 运行 总和列以外的任何列,return nil 因此它使用列绑定中的值。

对于 运行 总和列,简单但效率低下的实现类似于:

NSRange range = NSMakeRange(0, rowIndex + 1);
NSArray* rowsToSum = [self.itemController.arrangedObjects subarrayWithRange:range];
return [rowsToSum valueForKeyPath:@"@sum.price"];

当 运行 总和列中的单元格需要重新加载(重新计算)时,您还需要一种方法来通知 table 视图。您将使用 Key-Value Observing 来观察 self 键路径 @"itemController.arrangedObjects.price" 的变化。您可以在 -viewDidLoad-windowDidLoad 中进行设置。控制器完成后别忘了拆掉它。

发送更改通知时——即调用 -observeValueForKeyPath:ofObject:change:context: 时——您将在 table 视图上调用 -reloadDataForRowIndexes:columnIndexes: 以指示 [=98= 中的所有行索引] 应该重新加载总和列。

这应该可行,但一旦您获得大量行,效率就会非常低。

因此,为了优化,您应该缓存 运行 总和,但您需要注意适当地使缓存无效。

基本上,有一个像_cacheIsValid这样的实例变量。与所有实例变量一样,默认情况下它将从零(假)开始。在 -tableView:objectValueForTableColumn:row: 中,您将检查它是否有效。如果不是,您将构建它并记录它是有效的。然后,或者如果它已经有效,只需 return 请求行的元素。

要构建缓存,请迭代 self.itemController.arrangedObjects 计算 运行 总和并将每个值添加到数组的末尾。您可以根据需要使用原始类型的 C 样式数组或 NSNumberNSMutableArray。 (对于缓冲区使用 NSMutableData 可以简化 C 风格数组的内存管理。)

在告诉 table 视图重新加载 运行 总和列之前,您可以使 -observeValueForKeyPath:... 中的缓存无效。

为了提高效率,您可能会重新计算当时的缓存,并在进行时将值与现有缓存(如果有效)进行比较。在 NSMutableIndexSet 中仅累积缓存 运行 总和实际更改的那些行的行索引,并在对 -reloadDataForRowIndexes:columnIndexes: 的调用中使用它。这样,table 视图只会重新加载实际更改的单元格。