【问题标题】:NSOutlineView (Source List) EXC_BAD_ACCESS error with ARCARC 的 NSOutlineView(源列表)EXC_BAD_ACCESS 错误
【发布时间】:2013-08-08 23:02:50
【问题描述】:

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

【问题讨论】:

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

标签: cocoa automatic-ref-counting nsoutlineview


【解决方案1】:

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

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

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

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

更新:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多