【问题标题】:subclassing NSCell - [self objectValue] with drawInteriorWithFrame:inView: returns strange results子类化 NSCell - [self objectValue] with drawInteriorWithFrame:inView: 返回奇怪的结果
【发布时间】:2011-04-19 14:08:30
【问题描述】:

我的主窗口 NIB 文件中有一个 NSTableView,它使用动态创建的数据源 - 也就是说,字典数组是在需要时动态创建的 - 在我的一个类中。所以它不受IB中任何控制器的约束。

tableview 有 2 列具有子类 dataCell 的集合。

NSTableColumn *detailsColumn = [[tableView tableColumns] objectAtIndex:0];
imageColumnCell *fileDetails = [[[imageColumnCell alloc] init] autorelease];
[detailsColumn setDataCell:fileDetails];
[fileDetails setNumberOfUploads:numberOfFiles];

NSTableColumn *cancelColumn = [[tableView tableColumns] objectAtIndex:1];
cancelButtonCell *cancelCell = [[[cancelButtonCell alloc] init] autorelease];
[cancelColumn setDataCell:cancelCell];

<NSTableViewDataSource> 文件中,numberOfRowsInTableView: 设置为动态创建数组的正确计数,GDB 会在绘制表格时正确记录它。

现在问题来了。出于假设的原因,假设数据源的数组计数是 1

NSCell 的两个子类中,我都覆盖了drawInteriorWithFrame:inView: 方法来处理表格单元格内的所有绘图(图像、文本、按钮等)。每列的NSDictionary 包含一个字符串(第 1 列)和(第 2 列)的对象引用。

基于数据源中 1 个对象的示例,如果在 drawInteriorWithFrame:inView: 我要编写以下内容(在第 2 列中):

NSLog(@"drawInteriorWithFrame: in cancelButtonCell - %@", [self objectValue]);

GDB 中的预期结果(不点击表格或滚动等)应该是这样的 1 个实例:

[0000:000] drawInteriorWithFrame: in cancelButtonCell - <object: 0x123456>

如果我在表格中单击或滚动,那么它应该为表格视图中的每个操作返回相同的值。但是,在第一次加载时,我会得到这样的结果:

[0000:000] drawInteriorWithFrame: in cancelButtonCell - <object: 0x123af06>
[0000:000] drawInteriorWithFrame: in cancelButtonCell - <object: 0x12b3236>

如果有 2 个结果,那么我会得到 3 个日志项,其他时候是 4 个。在大多数情况下,该方法被调用的次数比它应该调用的次数多 1 次。

最近才出现的第二个问题是,如果您注意到上面的对象 ID,您会发现它们是不同的。如果我向数据源添加 1 项,当我调用 [self objectValue] 时,如果重新绘制表,则对象 ID 应该是相同的,因为它是一个引用 - 即。该对象已经在上一个类中为-alloc'd,我只是发送对象引用。

我希望这是有道理的,但最后一天我一直在努力想看看我是否在任何地方错误地复制了任何内容并且找不到任何问题。如果您需要更多代码,请告诉我。我也尝试过谷歌,但只得到了参考:

http://forum.soft32.com/mac/NSPopUpButtonCell-view-refresh-ftopict46690.html

提前致谢。

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {

  NSString *columnIdentifier = [tableColumn identifier]; 
  NSDictionary *theDict = [fileSourceArray objectAtIndex:row];

  MyAppMethods *appMethods = [MyAppMethods alloc];
  if([appMethods getIsComplete:self])
    return nil;

  if([columnIdentifier isEqualToString:@"fileCancel"]){
    if([[theDict objectForKey:columnIdentifier] isKindOfClass:[ASIFormDataRequest class]]){
      ASIFormDataRequest *fileUploadRequest = [theDict objectForKey:columnIdentifier];
      NSLog(@"in tableView:objectValueForTableColumn:row %@", fileUploadRequest);
      return fileUploadRequest;
    }
  }
  return [theDict objectForKey:columnIdentifier];
}

下面讨论的附加输出。

GDB 的输出

** 1 个文件,1 个 NSCell 集和子类 ** 这里的请求保持不变-(即没有复制)

[6619:903] <ASIFormDataRequest: 0x10ca9b0>
[6619:903] - (id)tableView:objectValueForTableColumn:row: /Users/byronrode/Desktop/Monika and Lubo/DSC_3379.jpg
[6619:903] imageColumnCell.m in - (void)drawInteriorWithFrame:inView: /Users/byronrode/Desktop/Monika and Lubo/DSC_3379.jpg
[6619:903] - (id)tableView:objectValueForTableColumn:row: <ASIFormDataRequest: 0x10ca9b0>
[6619:903] - (id)tableView:objectValueForTableColumn:row: /Users/byronrode/Desktop/Monika and Lubo/DSC_3379.jpg
[6619:903] imageColumnCell.m in - (void)drawInteriorWithFrame:inView: /Users/byronrode/Desktop/Monika and Lubo/DSC_3379.jpg
[6619:903] - (id)tableView:objectValueForTableColumn:row: <ASIFormDataRequest: 0x10ca9b0>

1 个文件,2 个 NSCell 的集合和子类

这里子类中的请求发生了变化——(即没有复制)

[6652:903] <ASIFormDataRequest: 0x103b390>
[6652:903] - (id)tableView:objectValueForTableColumn:row: /Users/byronrode/Desktop/Monika and Lubo/DSC_3379.jpg
[6652:903] imageColumnCell.m in - (void)drawInteriorWithFrame:inView: /Users/byronrode/Desktop/Monika and Lubo/DSC_3379.jpg
[6652:903] - (id)tableView:objectValueForTableColumn:row: <ASIFormDataRequest: 0x103b390>
[6652:903] cancelButtonCell.m in - (void)drawInteriorWithFrame:inView: <ASIFormDataRequest: 0x1221b00>
[6652:903] - (id)tableView:objectValueForTableColumn:row: /Users/byronrode/Desktop/Monika and Lubo/DSC_3379.jpg
[6652:903] imageColumnCell.m in - (void)drawInteriorWithFrame:inView: /Users/byronrode/Desktop/Monika and Lubo/DSC_3379.jpg
[6652:903] - (id)tableView:objectValueForTableColumn:row: <ASIFormDataRequest: 0x103b390>
[6652:903] cancelButtonCell.m in - (void)drawInteriorWithFrame:inView: <ASIFormDataRequest: 0x1227100>

【问题讨论】:

  • 表格是否显示不正确,或者您只是担心对-drawInteriorWithFrame: 的明显额外调用?另外,您是否在将其传递给单元格之前查看了表示的对象?这与单元格所说的对象值相比如何?
  • @josh-caswell - 表格显示正确(没有额外数据)。在我创建数据源的类中,实际对象、字典和包含字典的数组都包含相同的对象 ID。在 DataSource 中,tableView:objectValueForTableColumn:row: 中的对象仍然被正确引用,但是在我的 NSCell 子类中,引用发生了变化,并且所有额外的调用都与原始引用不同。我还注意到tableView:objectValueForTableColumn:row: 在数据源中有一个“行”的 2 列表被调用了 3 次。
  • 在进一步的测试中,我发现“额外调用”与列数有关,久不看更明显,所以这部分是有道理的。现在问题似乎出在哪里,如果我删除第二个 dataCell 子类cancelColumn(上图),那么引用的对象就会被正确识别。我已经用我的- tableView:objectValueForTableColumn:row: 方法更新了这个问题。
  • 您的两个表格列都使用同一个自定义单元格类吗?
  • 不。每个都使用一个单独的单元类。它曾经是一列,使用一个自定义单元格,但鼠标跟踪存在性能问题,因此我将其拆分,以便跟踪与需要点击跟踪的列相关。

标签: objective-c cocoa xcode4 nscell


【解决方案1】:

如果它显示正确,我认为没有什么可担心的。表格视图在完成绘图之前询问其表格列是否有“虚拟”单元格;我怀疑这是额外的-draw... 电话的原因。此外,单元格在设置时复制其对象值,因此显然会给它一个新地址。

响应您发布的日志消息:

我不是 100% 清楚这些日志何时发布以及它们显示的内容,但这看起来就像我期望看到的那样。在tableView:objectValueForTableColumn:row: 中,您正在打印在字典中 的值,这与原始ASIFormDataRequest 相同。在drawInteriorWithFrame:inView: 中,您正在打印单元格的objectValue,它是原始的副本(即,一个新对象,在内存中具有不同的地址)。

【讨论】:

  • 这是有道理的,但是当使用一个或两个自定义列单元格时,复制肯定会是相同的。除了在这种情况下,使用 2 个自定义单元格时地址会更改。我在问题中添加了更多信息。也许现在它会更有意义。
  • 在我看来,这些是不会影响您的程序的 AppKit 实现细节。我还是说“别担心”。为了高效地完成他们的工作,表格视图、表格列和NSCell 都在幕后做着你可能没想到的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 2012-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多