我正在编写一个带有基于视图的NSTableView的沙盒ARC应用程序,该应用程序接受拖放文件(NSURL
)。我在以下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;
}
我可以将一个文件拖到表格视图中,然后显示正确。当我拖动第二个文件时,我收到此错误:
*** 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(默认情况下);怎么能从我这里得到释放和重新创造?
我已经拿出两个黑客来解决这个问题:
我在这里缺少什么?这些变通办法不是必需的。
答案 0 :(得分:2)
调用-makeViewWithIdentifier:owner:将导致-awakeFromNib消息发送给所有者。这是记录在案但仅在头文件中(编辑:主文档已更新以引用此内容)。
我想你的文件数组只是在-awakeFromNib中重新初始化。
给定情况下的解决方案(加载视图原型而不是nib)只是将nil作为所有者传递。加载已注册的nib的其他实现(请参阅-registerNib:forIdentifier :)可能需要所有者,该所有者可能是委托(或不是)。因此,可能必须检测并捕获对-awakeFromNib
的多次调用。设置一个属性以标记nib加载并且只执行一次所需的初始化是微不足道的。
请注意,此方法的Apple文档已更新,以反映这一点:
请注意,每次调用此方法时都会调用awakeFromNib, 这意味着awakeFromNib也会在所有者身上调用,即使是 老板已经醒了。