0

语境

我有一个 2 列、基于单元格的 NSTableView,由 NSArrayController 管理。

  • 第一列填充有复选框以指示该值是否已启用。
  • 第二列代表元素的名称。

该视图链接到 NSSearchField,因此根据将搜索字符串与第 2 列中的字符串进行比较的谓词进行过滤。

更改搜索字符串时,视图正确显示并按预期过滤。

要求

我只需要允许用户最多启用 5 行。为了实现这一点,我正在监视支持数组的更改并跟踪启用条目的数量。如果计数超过 5,则我会通过警报通知用户并通过获取选定的行索引然后在后备数组中禁用该索引来取消选择先前启用的条目。我在 [willChange.. ..didChange] KVO 块中执行此操作。

这在视图未排序时按预期工作,但显然会导致问题,因为所选行不再对应于数组中的适当索引。

因此,如果视图被过滤(搜索字符串不为空),我使用以下代码获取所选单元格的字符串值。然后我遍历数组并禁用匹配字符串的条目。

NSInteger selectedRow = [_tv_TableView selectedRow];
NSTableColumn* column=  [_tv_TableView tableColumns][1];
NSCell* cell = [column dataCellForRow:row];
NSString* cellValue = (NSString*)[cell stringValue];
return cellValue;

问题

尽管选定的行总是准确的,但从代表单元格中获取值却不是。看起来最初返回的值是正确的,但是即使选择的索引仍然正确,选择其他行也会从下一行返回数据。我还观察到它从视图中的几行返回值。

更新

在进一步测试之后,第一次应用过滤器似乎可以工作,但是通过不同的字符串过滤会保留第一个选定单元格的单元格值以应对特定的不稳定。

IE:

  1. 加载窗口并选择 6 个项目
  2. 取消选择第 6 项并警告用户
  3. 应用过滤器
  4. 选择新的第 6 项
  5. 取消选择第 6 项并警告用户
  6. 在同一过滤器中选择不同的第 6 项
  7. 取消选择第 6 项并警告用户
  8. 输入新过滤器
  9. 选择新的第 6 项
  10. 取消选择第 6 项并警告用户
  11. 从同一过滤器中选择新的第 6 项
  12. 所选索引正确,但所选行的值与之前的选择相同
  13. 用户反复警告,因为没有取消选择正确的条目,导致 6 个永久选中的条目。

但是,仍然存在返回以下行值而不是先前选择的项目的情况。

问题

我的问题是:

  1. 我是否以正确的方式为过滤列表获取选定的行?
  2. 即使列表已排序,如何根据所选行一致地检索第 2 列的字符串值?

感谢您的时间。

解决方案

我通过更改从以下位置获取单元格的代码解决了这个问题:

NSInteger selectedRow = [_tv_TableView selectedRow];
NSTableColumn* column=  [_tv_TableView tableColumns][1];
NSCell* cell = [column dataCellForRow:row];
NSString* cellValue = (NSString*)[cell stringValue];
return cellValue;

至:

NSCell* cell = [_tv_TableView preparedCellAtColumn:1 row:row];
NSString* cellValue = (NSString*)[cell stringValue];
return cellValue;
4

2 回答 2

1

简单的解决方案是将表的selectionIndexes绑定绑定到数组控制器的同名属性。然后,您可以访问阵列控制器-selectedObjects以查找所选对象。

当您从表中有一行(或索引)时,无论它是否被选中,您都可以使用-arrangedObjects. NSArrayController这将始终对应于索引。

细胞被重复使用。没有一个单元格与每个(行、列)位置相关联。每列都有一个单元格,但每次需要绘制或以其他方式操作一行时,都会为每一行重新配置它。这就是为什么你需要准备好的细胞。也就是说,单元在概念上位于视图层(在模型-视图-控制器中)。你所做的应该在控制器和模型域中,所以你不应该咨询视图层(也不应该需要)。

于 2014-07-30T23:00:22.537 回答
0

由于某种原因,在更改 NSSearchField 中的过滤器时,项目的内部表示未更新。这是返回的值与实际视图不一致。

我通过更改从以下位置获取单元格的代码解决了这个问题:

NSInteger selectedRow = [_tv_TableView selectedRow];
NSTableColumn* column= [_tv_TableView tableColumns][1];
NSCell* cell = [column dataCellForRow:row];
NSString* cellValue = (NSString*)[cell stringValue];
return cellValue;

至:

NSCell* cell = [_tv_TableView preparedCellAtColumn:1 row:row];
NSString* cellValue = (NSString*)[cell stringValue];
return cellValue;

在此之前,我还尝试使用以下方法强制视图手动更新:

[_tv_TableView reloadData];

但这对结果没有影响。我仍然有兴趣确切地知道为什么会发生这种情况。如果我发现,那么我会更新答案。

于 2014-07-30T21:26:16.627 回答