2

我有一个启用 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
4

1 回答 1

3

我刚刚在我的代码中发现了类似的崩溃。我将描述原因对我来说是什么......我很确定这里同样适用,但我没有测试你的代码。

请注意,awakeFromNib如果您有多个 NIB,则可以多次调用它。我相信如果您将 NSTableCellView 对象嵌入到您的 XIB 文件中的 NSOutlineView 中,就会出现这种情况,当您makeViewWithIdentifier:owner:outlineView:viewForTableColumn:item:.

因为您是在其中创建模型对象(stan等)awakeFromNib,所以在这些多次调用期间会重新创建它们。每次调用时,ARC 都会清理以前的模型对象,但 NSOutlineView 仍在引用它们,因此当 NSOutlineView 尝试向它们询问更多信息时会发生崩溃。

解决方法是将模型对象的创建移出awakeFromNib,也许改为init方法。

更新:

其他一些小点......我也花了一段时间才找到魔法outlineView:viewForTableColumn:item:方法的文档。出于某种原因,它是 NSOutlineViewDelegate 协议的一部分,而不是 NSOutlineViewDataSource。我相信如果你实现了这个方法,你就不需要实现outlineView:objectValueForTableColumn:byItem:.

于 2014-06-27T13:22:59.503 回答