好的,所以如果你不得不投票,但是我准备通过一些东西,因为这让我发疯了。我有一个core data
应用程序(OS X),通过NSTableViews
连接了一对NSArrayControllers
(基于单元格)。我有一些自定义方法的实体类'设置。我可以添加,删除,编辑和使用数据做各种事情 - 一切都很好。
我决定为运行总和添加一个新列,并使用我所见过的@sum
。无论我做什么,我都会收到错误。
我有一个实体“商店”和另一个实体“商品”,他们有一个多对多的关系。在Item实体中,我有一个名称和价格属性。
在主窗口上,我有NSTableView
个NSArrayController
的控制器,一个用于商店,一个用于商品。项目NSArrayController
的内容由商店控制器控制 - 所选项目。
我在Item NSTableView
中添加了一个新列,将其绑定到Item Controller并将其模型键路径设置为@ sum.price - 这会导致错误。
我可能遗漏了一些简单的想法,如何正确地做到这一点?
谢谢。
- [编辑] ----
存储NSArrayController
:
- 对象控制器
- 实体名称:商店
ManagedObjectContext
项目NSArrayController
:
对象控制器
内容集:
绑定到存储阵列控制器
控制器键:选择
模型关键路径:项目
项目NSTableView
:
第一栏:
绑定到项目数组控制器
控制器密钥:arrangeObjects
模型关键路径:名称
第二栏:
新的总和栏目:
绑定到项目数组控制器
控制器密钥:arrangeObjects
模型关键路径:@ sum.price
我收到的错误是:“实体项目与密钥”@sum“不符合密钥值编码。”
答案 0 :(得分:1)
考虑你的第一栏。它与项目控制器arrangedObjects
,name
绑定。每个单元格都有一个名称数组吗?不。每个人都有一个名字。
虽然列绑定有时表示为Item Controller.arrangedObjects.name
之类的关键路径,但它实际工作的方式是整个列显示arrangedObjects
,每行一个元素,但{{1分别应用于该集合的每个元素。因此,每个单元格都有一个名称。
现在考虑你的新专栏。行再次对应于项目控制器的name
,但模型关键路径分别应用于每个元素。但模型关键路径包含一个集合运算符arrangedObjects
,它不适用于单个元素(@sum
实体)。因此错误。
您可以创建一个文本字段(表格外部),显示所选商店所有商品的价格总和。您可以将文本字段的值绑定绑定到项目控制器Item
,arrangedObjects
。文本字段的工作方式与表格列不同,因为它只显示一个内容。它确实使用了@sum.price
的结果。集合运算符将应用于集合。
您还可以将文本字段绑定到项目控制器 [ItemController valueForKeyPath:@"arrangedObject.@sum.price"]
,selection
,以显示所选项目的价格总和在项目表中。
如果我理解你的意思,绑定不提供任何获得运行总和的方法(第一行显示第一项的价格,第二行显示第一项和第二项的价格总和,等等。)。这样的运行总和将取决于上下文。给定行的值将取决于先前行的值。例如,对表进行不同的排序意味着给定项旁边的运行总和会发生变化,因为它之前的项集已经改变。绑定不能这样做。他们不了解职位,指数或兄弟姐妹。
更新
要获得运行总和,您需要不对列使用绑定。如果尚未使用@sum.price
,请使您的视图或窗口控制器采用。然后将表格视图的NSTableViewDataSource
插座连接到它。
在您的数据源类中,实现dataSource
。检查专栏-tableView:objectValueForTableColumn:row:
。对于除运行总和列以外的任何列,请返回identifier
,以便它使用列绑定中的值。
对于运行总和列,直接但效率低下的实现类似于:
nil
当需要重新加载(重新计算)运行总和列中的单元格时,您还需要一种方法来通知表格视图。您可以使用键值观察来观察NSRange range = NSMakeRange(0, rowIndex + 1);
NSArray* rowsToSum = [self.itemController.arrangedObjects subarrayWithRange:range];
return [rowsToSum valueForKeyPath:@"@sum.price"];
关键路径self
的变化。您可以在@"itemController.arrangedObjects.price"
或-viewDidLoad
中进行设置。当控制器完成时,不要忘记把它拆掉。
当传递更改通知时 - 即调用-windowDidLoad
时 - 您将在表视图上调用-observeValueForKeyPath:ofObject:change:context:
以指示应重新加载运行总和列中的所有行索引。
这应该可行但是一旦你获得了大量的行,它将会非常低效。
因此,要进行优化,您应该缓存运行总和,但需要注意使缓存无效。
基本上,有一个像-reloadDataForRowIndexes:columnIndexes:
这样的实例变量。与所有实例变量一样,默认情况下它将从零开始(false)。在_cacheIsValid
中,您需要检查它是否有效。如果不是,您将构建它并记录它是有效的。然后,或者如果它已经有效,只需返回所请求行的元素。
要构建缓存,请迭代-tableView:objectValueForTableColumn:row:
计算运行总和,并将每个值添加到数组的末尾。您可以根据需要使用C样式的基本类型数组或self.itemController.arrangedObjects
NSMutableArray
个NSNumber
。 (通过使用NSMutableData
作为缓冲区,可以简化C风格数组的内存管理。)
在告诉表视图重新加载运行总和列之前,您将使-observeValueForKeyPath:...
中的缓存无效。
对于效率的下一步,您可以在那时重新计算缓存并将值与现有缓存(如果它有效)进行比较。仅在NSMutableIndexSet
的行索引中累积缓存的运行总和实际更改的行,并在-reloadDataForRowIndexes:columnIndexes:
的调用中使用该行索引。这样,表视图仅重新加载实际更改的单元格。