来自outlineView的EXC_BAD_ACCESS:child:ofItem

时间:2013-10-06 21:34:25

标签: objective-c cocoa nsoutlineview

请解释为什么我对下面这行已经注释掉的问题有疑问。

它在outlineView中引起了一个EXC_BAD_ACCESS:objectValueForTableColumn:byItem:。

全班的要点是:https://gist.github.com/onato/9d12bbbf5c4135673f24

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{
    if (!item) {
        item = self.data;
    }
    id returnValue = @"";
    if ([item isKindOfClass:[NSArray class]]) {
        returnValue = @"value";//[item objectAtIndex:index];
    }

//    return @{@"index":@(index), @"value":returnValue}; // produces EXC_BAD_ACCESS in outlineView:objectValueForTableColumn:byItem:
    return returnValue;
}

我尝试用这个数据源创建一个非常基本的项目而没有别的东西,我仍然看到了问题。

2 个答案:

答案 0 :(得分:1)

您无法在outlineView:child:ofItem:中动态制作项目。您的所有项目必须已经存在,或者至少在之后继续存在,直到它们被删除(即代表用户从视图模型中删除)或者直到大纲视图显示的内容被删除为止(例如,文件已关闭)。

字典文字(@{ … })表示此时字典的创建。每当您的程序到达该行时,它将创建一个新词典,每次,即使对于同一项目的同一个孩子也是如此。 (当字典包含不恒定的内容时,这必然是正确的,例如indexreturnValue的值。)

即使你保留了词典,但是使用普通的旧词典和/或数组可以很快地制作非常繁琐的代码。

解决方案

使用两个属性创建NSObject的简单子类:

  • value(或更具体的内容),这是您在大纲视图中显示的任何类型的值
  • children(或更具体的内容),这是每个项目可能包含的任何后代项目的数组

然后保留这些对象的数组。当询问nil的孩子时,返回该阵列中的一个对象。当被要求提供项目的子项时,该项目将是其中一个对象,因此请返回其中一个children

当询问项目的对象值(我假设是您的唯一列)时,返回项目的value。如果您有多列,请为每列添加一个属性。

最重要的是,在大纲视图甚至可见之前创建所有这些对象并保持它们直到完成它们(无论是通过删除项目还是通过解除视图)。不要根据需要创建项目,然后期望大纲视图为您挂起 - 这不是它的工作;这是你的作为控制器的工作。

这些项目不必是同一个班级;如果它对你的应用程序有意义,你可以拥有Foos拥有酒吧和酒吧拥有Bazzes。如果您的需求很简单,那么将一切都变成Foo可能更有意义。做任何有意义的事情。无论哪种方式,自定义对象都会为您的代码增添清晰度。

更重要的是,当您在地板上放置自定义对象而不是删除由文字创建的字典时,它也更加明显。更容易看到return [[Foo alloc] init…]并被提醒“哦,对,我需要坚持下去。”

答案 1 :(得分:0)

一般来说,如果没有初始化就可以返回一个值,这是不好的做法。

id returnValue;应该是id returnValue = nil; 具体来说,如果self.data中有一个实际上不是NSArray(或它的子代)的对象,那么你将返回一个未定义的指向对象的指针,这几乎肯定会导致一些不幸的事情。

您有什么保证该指数实际上在项目的范围内? 这似乎会产生一个糟糕的访问异常?