2

我正在编写一个带有基于视图的 NSTableView 的沙盒 ARC 应用程序,该应用程序接受拖放文件(NSURLs)。NSTableViewDelegate我在以下方法中遇到了一些重大的奇怪现象:

- (NSView *)tableView:(NSTableView *)tv
   viewForTableColumn:(NSTableColumn *)tc
                  row:(NSInteger)row
{
    // `files' is an NSMutableArray* ivar containing NSURLs
    // that have been dropped into this table
    NSURL *url = [files objectAtIndex:row];
    NSString *fileName = [url lastPathComponent];
    NSImage *icon = [self iconForURL:url];

    NSTableCellView *view = [tv makeViewWithIdentifier:[tc identifier] owner:self];
    [[view textField] setStringValue:fileName];
    [[view imageView] setImage:icon];

    return view;
}

我可以将一个文件拖到表格视图中,它可以正确显示。当我拖动第二个文件时,出现此错误:

*** 取消拖动,因为在拖动会话期间引发了异常 'NSRangeException'(原因 '*** -[__NSArrayM insertObject:atIndex:]: index 1 beyond bounds for empty array')

通过调试器,我发现files在调用makeViewWithIdentifier:owner:. 我认为这是我不理解的 ARC 的某些方面,但在我看来,该对象强烈引用了它自己的 ivar(默认情况下);它怎么能从我下面被释放和重新创造出来?

我想出了两个技巧来解决这个问题:

  1. 将 ivar 作为表格单元格视图的所有者传递(希望在未来的版本中它将继续保持强引用);或者
  2. 创建一个局部变量以指向 ivar 的对象并将 ivar 重新分配给旧对象(这显然是浪费,因为它同时创建了一个替换数组)。

我在这里想念什么?这些变通方法应该不是必需的。

4

1 回答 1

2

调用 -makeViewWithIdentifier:owner: 将导致向所有者发送 -awakeFromNib 消息。这已记录在案,但仅在头文件中(编辑:主文档已更新以引用此文件)。

我想你的文件数组只是在 -awakeFromNib 中重新初始化。

给定情况下的解决方案(加载视图原型而不是 nib)只是将 nil 作为所有者传递。加载已注册 nib 的其他实现(请参阅 -registerNib:forIdentifier:)可能需要所有者,该所有者可能是委托人(或不是委托人)。-awakeFromNib因此,可能必须检测和捕获多个调用。设置一个属性来标记 nib 加载并且只执行一次所需的初始化是微不足道的。

请注意,此方法的 Apple 文档已更新以反映这一点:

请注意,每次调用此方法时都会调用 awakeFromNib,这意味着即使所有者已经醒来,也会在所有者上调用 awakeFromNib。

于 2013-12-19T12:09:51.737 回答