调用 makeViewWithIdentifier:owner: 导致 ARC 重新创建 ivar

2024-03-14

我正在编写一个沙盒 ARC 应用程序,其中包含基于视图的 NSTableView,它接受拖放文件(NSURLs)。我在下面遇到了一些明显的奇怪之处NSTableViewDelegate method:

- (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;
}

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


*** Canceling drag because exception 'NSRangeException' (reason '*** -[__NSArrayM insertObject:atIndex:]: index 1 beyond bounds for empty array') was raised during a dragging session  

单步调试器,我发现files“变成空”——实际上成为一个新的对象实例——在调用之后makeViewWithIdentifier:owner:。我认为这是我不理解的 ARC 的某些方面,但在我看来,该对象对其自己的 ivar 有很强的引用(默认情况下);它怎么可能从我的手下被释放并重新创造出来?

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

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

我在这里缺少什么?这些解决方法应该不是必要的。


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

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

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

调用 makeViewWithIdentifier:owner: 导致 ARC 重新创建 ivar 的相关文章

随机推荐