调用makeViewWithIdentifier:owner:使ARC重新创建ivar [英] Calling makeViewWithIdentifier:owner: causes ARC to re-create ivar
问题描述
我正在编写一个带有基于视图的NSTableView的沙盒ARC应用程序,该应用程序接受拖放的文件(NSURL
s).我在以下NSTableViewDelegate
方法中遇到了一些重大的陌生感:
I'm writing a sandboxed ARC app with a view-based NSTableView that accepts dragged-and-dropped files (NSURL
s). I ran into some significant strangeness in the following 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;
}
我可以将一个文件拖到表格视图中,然后正确显示.当我拖动第二个文件时,出现此错误:
I can drag one file into the table view, and it displays correctly. When I drag a second file, I get this error:
*** 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(默认情况下).怎么能从我的身下释放出来并重新创建它?
Stepping through the debugger, I discovered that files
"becomes empty" -- actually becomes a new object instance -- after the call to makeViewWithIdentifier:owner:
. I assume this is some aspect of ARC that I don't understand, but it seems to me that the object has a strong reference to its own ivar (by default); how could it get released and re-created out from under me?
我想出了两种方法来解决此问题:
I have come up with two hacks to work around this:
- 通过ivar作为表单元格视图的所有者(希望在将来的版本中它将继续拥有强大的引用);或
- 创建一个局部变量以指向ivar的对象并将ivar重新分配给旧对象(这显然很浪费,因为它同时创建了一个替换数组).
我在这里想念什么?这些解决方法是不必要的.
What am I missing here? These workarounds should not be necessary.
推荐答案
调用-makeViewWithIdentifier:owner:将导致-awakeFromNib消息发送给所有者.已记录此文件,但仅在头文件中记录(主要文档已更新为引用此文件).
Calling -makeViewWithIdentifier:owner: will cause an -awakeFromNib message to be sent to owner. This is documented but only in the header file ( the main documentation has been updated to refer to this).
我想您的文件数组只是在-awakeFromNib中重新初始化.
I imagine that your files array is simply becoming reinitialised in -awakeFromNib.
在给定情况下(加载视图原型而不是笔尖)的解决方案只是将nil作为所有者.加载已注册笔尖的其他实现(请参见-registerNib:forIdentifier :)可能需要所有者,该所有者可以是委托人(也可以不是委托人).因此,可能必须检测并捕获对-awakeFromNib
的多次调用.设置属性以标记笔尖加载很简单,并且只执行一次所需的初始化.
The solution in the given case (which is loading a view prototype rather than a nib) is simply to pass nil as the owner. Other implementations which load registered nibs (see -registerNib:forIdentifier:) may likely require an owner, which may be the delegate (or not). So multiple calls to -awakeFromNib
may have to be detected and trapped. It is trivial to set a property to flag nib loading and only perform required initialisation once.
请注意,此方法的Apple文档已更新以反映此情况:
Note that the Apple docs for this method have been updated to reflect this:
请注意,每次调用此方法时都会调用awakeFromNib, 这意味着awakeFromNib也会被所有者调用,即使 所有者已经醒了.
Note that awakeFromNib is called each time this method is called, which means that awakeFromNib is also called on owner, even though the owner is already awake.
这篇关于调用makeViewWithIdentifier:owner:使ARC重新创建ivar的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!