Cocoa NSOutlineView(源列表)EXC\u错误\u访问错误与ARC

Cocoa NSOutlineView(源列表)EXC\u错误\u访问错误与ARC,cocoa,automatic-ref-counting,nsoutlineview,Cocoa,Automatic Ref Counting,Nsoutlineview,我有一个启用ARC的项目,在IB中我创建了一个窗口,其中包含源代码列表组件,我认为它只是一个配置的NSOutlineView。我正在使用神奇的委托方法: - (id)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item 对此,我根本找不到任何文档。一旦这个方法被实现,我的大纲视图中的根节点就会出现,在这个节点上我的整个模型都会被释放。然后,当我

我有一个启用ARC的项目,在IB中我创建了一个窗口,其中包含源代码列表组件,我认为它只是一个配置的
NSOutlineView
。我正在使用神奇的委托方法:

- (id)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
对此,我根本找不到任何文档。一旦这个方法被实现,我的大纲视图中的根节点就会出现,在这个节点上我的整个模型都会被释放。然后,当我尝试展开根节点时,应用程序立即崩溃,因为模型不再存在

如果我不使用这个方法,我的模型仍然存在,源列表可以工作,但是没有一个单元格出现(可以理解)。我真的没有在这里做任何花哨的事

我以前从未遇到过ARC这样的问题,但现在已经很晚了,所以我有可能做了一些愚蠢的事情,只是看不见而已。以下是完整的代码:

@implementation RLListController

- (void)awakeFromNib
{
    RLPerson *stan = [[RLPerson alloc] initWithName:@"Stan"];
    RLPerson *eric = [[RLPerson alloc] initWithName:@"Eric"];
    RLPerson *ken = [[RLPerson alloc] initWithName:@"Ken"];
    RLPerson *andrew = [[RLPerson alloc] initWithName:@"Andrew"];
    RLPerson *daniel = [[RLPerson alloc] initWithName:@"Daniel"];
    RLPerson *aksel = [[RLPerson alloc] initWithName:@"Aksel"];

    [stan addChild:eric];
    [stan addChild:ken];
    [stan addChild:andrew];

    [ken addChild:daniel];
    [daniel addChild:aksel];

    self.people = [@[stan] mutableCopy];
}

#pragma mark - Source List dataSource

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
    RLPerson *person = item;
    return (item != nil) ? [person.children count] : [self.people count];
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
    RLPerson *person = item;
    return (item != nil) ? [person.children count] > 0 : YES;
}

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{
    RLPerson *person = item;
    return (item != nil) ? [person.children objectAtIndex:index] : [self.people objectAtIndex:index];
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
    RLPerson *person = item;
    return person.name;
}

- (id)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
    RLPerson *person = item;
    NSTableCellView *cell = [outlineView makeViewWithIdentifier:@"DataCell" owner:self];
    cell.objectValue = person;
    [cell.textField setStringValue:person.name];
    return cell;
}

@end


@implementation RLPerson

- (id)initWithName:(NSString *)name
{
    self = [super init];
    if(self)
    {
        _name = [name copy];
        _children = [[NSMutableArray alloc] initWithCapacity:0];
    }
    return self;
}

- (void)addChild:(RLPerson *)child
{
    [_children addObject:child];
}

- (void)dealloc
{
    NSLog(@"dealloc");
}

@end

我刚刚在我的代码中发现了一个类似的崩溃。我会描述我的原因。。。我很确定这同样适用于这里,但我还没有测试过你的代码

请注意,如果您有多个NIB,则可以多次调用
awakeFromNib
。如果您在XIB文件中的NSOutlineView中嵌入了NSTableCellView对象,我相信这种情况就是如此,这些对象是在调用
makeViewWithIdentifier:owner:
中的
outlineView:viewForTableColumn:item:
时提取的

由于您正在
awakeFromNib
中创建模型对象(
stan
等),因此在这些多个调用过程中会重新创建它们。每次调用时,ARC都会清理以前的模型对象,但NSOutlineView仍在引用它们,因此,当NSOutlineView试图向它们询问更多信息时,会出现后一次崩溃

解决方法是将模型对象创建从
awakeFromNib
中移出,或者移到
init
方法中

更新:


还有一些小问题。。。我还花了一些时间找到magic
outlineView:viewForTableColumn:item:
方法的文档。出于某种原因,它是NSOutlineViewDelegate协议的一部分,而不是NSOutlineViewDataSource。我相信如果你实现了这个方法,你就不需要实现
outlineView:objectValueForTableColumn:byItem:

当你用僵尸模板在Instruments下运行这个时会发生什么?我想我看到了同样的问题:你有没有找到这个问题的根源?@Ashley No,我放弃了这个项目。谢谢你的回复。我想我最终解决了。。。看看我的答案。