1

请解释为什么我在注释掉的下面的行中遇到问题。

它在 outlineView:objectValueForTableColumn:byItem: 中导致 EXC_BAD_ACCESS。

完整课程的要点在: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;
}

我已经尝试用这个数据源创建一个非常基本的项目,但我仍然看到了问题。

4

2 回答 2

1

你不能在outlineView:child:ofItem:. 您的所有项目必须已经存在,或者至少在之后继续存在,直到它们被删除(即,代表用户从视图模型中删除)或直到大纲视图显示的任何内容被取消(例如,文档关闭)。

字典文字 ( @{ … }) 表示此时字典的创建。每当您的程序到达该行时,它都会创建一个新字典,每次,甚至为同一个 item 的同一个子项。(当字典包含一些不恒定的内容时,这必然是正确的,例如 和 的值indexreturnValue

但是,即使您保留字典,为您的模型使用普通的旧字典和/或数组也会很快产生非常复杂的代码。

解决方案

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

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

然后保留这些对象的数组。当要求 的子级时nil,返回该数组中的一个对象。当询问某个项目的子项时,该项目将是这些对象之一,因此返回它的一个children

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

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

这些项目不必都是同一类;如果它对你的应用有意义,你可以让 Foos 拥有 Bars 和 Bars 拥有 Bazzes。如果您的需求很简单,那么将所有内容都设为 Foo 可能更有意义。做任何有意义的事。无论哪种方式,自定义对象都可以使您的代码更加清晰。

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

于 2013-10-07T02:14:44.937 回答
0

一般来说,不经过初始化就可以返回一个值是不好的做法。

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

您有什么保证索引实际上在项目范围内?这似乎会产生错误的访问异常?

于 2013-10-06T21:41:51.423 回答