好的,所以如果需要的话就把它否决,但是我已经准备好要通过一些事情了,因为这使我发疯。我有一个core data
应用程序(OS X),通过NSTableViews
连接了几个NSArrayControllers
(基于单元)。我有一些自定义方法的Entity类设置。我可以添加,删除,编辑数据并进行各种处理-一切都很好。
我决定为运行总和添加新列,并使用@sum
,如我所见。无论我做什么,我都会不断收到错误消息。
我有一个实体“ Store”和另一个实体“ Item”,它们有一对多的关系。在项目实体中,我具有名称和价格属性。
在主窗口中,我有两个NSTableView
的NSArrayController
控制器,一个用于存储,一个用于物料。项目NSArrayController
的内容由存储控制器-所选项目控制。
我在Item NSTableView
中添加了新列,将其绑定到Item Controller,并将其模型键路径设置为@ sum.price-这会导致错误。
我可能缺少一些简单的东西,对如何正确执行此操作有任何想法吗?
谢谢。
- [编辑] - -
商店NSArrayController
:
-对象控制器
-实体名称:商店
ManagedObjectContext
绑定到主控制器的ManagedObjectContext
项目NSArrayController
:
对象控制器
实体名称:项目
内容集:
绑定到存储阵列控制器
控制器键:选择
型号关键路径:项目
项目NSTableView
:
第一栏:
绑定到项目数组控制器
控制器键:rangedObjects
型号密钥路径:名称
第二栏:
相似,型号关键路径:价格
新的总和列:
绑定到项目数组控制器
控制器键:rangedObjects
模型密钥路径:@ sum.price
我收到的错误是:“实体Item不符合键“ @sum”的编码标准。
最佳答案
考虑您的第一列。它绑定到项目控制器arrangedObjects
,name
。每个单元格都有一个名称数组吗?不。每个人都有一个名字。
尽管有时将列绑定表示为像Item Controller.arrangedObjects.name
这样的键路径,但实际上它的工作方式是该列整体上显示arrangedObjects
,每行一个元素,但是name
应用于该行的每个元素单独设置。因此,每个单元格都有一个名称。
现在考虑您的新专栏。这些行再次对应于Item Controller的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:
以指示应重新加载运行总和列中的所有行索引。那应该行得通,但是一旦您获得大量的行,它将效率极低。
因此,为了进行优化,您应该缓存运行总和,但是需要注意适当地使缓存无效。
基本上,有一个实例变量,例如
_cacheIsValid
。像所有实例变量一样,默认情况下它将以零(false)开头。在-tableView:objectValueForTableColumn:row:
中,您将检查其是否有效。如果不是,则将其构建并记录其有效。然后,或者如果它已经有效,则只需返回所请求行的元素。要构建缓存,请遍历
self.itemController.arrangedObjects
并计算运行总和,并将每个值添加到数组的末尾。您可以根据需要使用基本样式类型的C样式数组或NSMutableArray
的NSNumber
。 (可以通过将NSMutableData
用于缓冲区来简化C样式数组的内存管理。)在告诉表视图重新加载运行总和列之前,您将使
-observeValueForKeyPath:...
中的缓存无效。为了提高效率,您可以在那时重新计算缓存,然后将值与现有缓存(如果有效)进行比较。在
NSMutableIndexSet
中仅累积那些实际运行的总和发生更改的行的行索引,并在对-reloadDataForRowIndexes:columnIndexes:
的调用中使用该行索引。这样,表视图仅重新加载实际更改的单元格。
关于objective-c - 类别对键@sum的键值编码不兼容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28622617/