调用makeViewWithIdentifier:owner:使ARC重新创建ivar [英] Calling makeViewWithIdentifier:owner: causes ARC to re-create ivar

查看:205
本文介绍了调用makeViewWithIdentifier:owner:使ARC重新创建ivar的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个带有基于视图的NSTableView的沙盒ARC应用程序,该应用程序接受拖放的文件(NSURL s).我在以下NSTableViewDelegate方法中遇到了一些重大的陌生感:

I'm writing a sandboxed ARC app with a view-based NSTableView that accepts dragged-and-dropped files (NSURLs). 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:

  1. 通过ivar作为表单元格视图的所有者(希望在将来的版本中它将继续拥有强大的引用);或
  2. 创建一个局部变量以指向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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆