我正在实现一个简单的文件浏览器(在NSOutlineView
中)并在扩展我的根节点时遇到EXC_BAD_ACCESS
。我的NSOutlineViewDataSource
按以下方式返回子项:
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
if (!item) {
// Root node
return @"Files";
}
NSFileManager *manager = [NSFileManager defaultManager];
NSError *error = nil;
return [[manager contentsOfDirectoryAtPath:@"/" error:&error] objectAtIndex:index];
}
此方法返回的NSString
正在自动释放,当AppKit代码在此处调用时:
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
NSString *identifier = [item isEqualToString:@"Files"] ? @"HeaderCell" : @"DataCell";
NSTableCellView *cell = [outlineView makeViewWithIdentifier:identifier owner:self];
cell.textField.stringValue = item;
return cell;
}
item
已经消失。这是该项目生命周期的仪器屏幕截图:
我不确定我做错了什么 - 我无法明确retain
任何事情(也不应该!)因为ARC已启用,但子项仍然丢失。
编辑:实际崩溃的Stacktrace:
0 CoreFoundation -[__NSCFString retain]
1 Spark -[SPFileBrowserController outlineView:child:ofItem:] /Users/Craig/projects/Spark/Spark/SPFileBrowserController.m:29
2 AppKit loadItemEntryLazyInfoIfNecessary
3 AppKit -[NSOutlineView _rowEntryForChild:ofParent:requiredRowEntryLoadMask:]
4 AppKit -[NSOutlineView _expandItemEntryChildren:atStartLevel:expandChildren:andInvalidate:]
5 AppKit -[NSOutlineView _expandItemEntry:expandChildren:startLevel:]
6 AppKit -[NSOutlineView _batchExpandItemsWithItemEntries:expandChildren:]
7 AppKit -[NSOutlineView expandItem:expandChildren:]
8 AppKit -[NSOutlineView _doUserExpandOrCollapseOfItem:isExpand:optionKeyWasDown:]
9 AppKit -[NSOutlineView _outlineControlClicked:]
10 AppKit -[NSApplication sendAction:to:from:]
11 AppKit -[NSControl sendAction:to:]
12 AppKit -[NSCell _sendActionFrom:]
13 AppKit -[NSCell trackMouse:inRect:ofView:untilMouseUp:]
14 AppKit -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:]
15 AppKit -[NSControl mouseDown:]
16 AppKit -[NSWindow sendEvent:]
17 AppKit -[NSApplication sendEvent:]
18 AppKit -[NSApplication run]
19 AppKit NSApplicationMain
20 libdyld.dylib start
编辑2:项目现已附加。修改SPFileUtil
childrenOfFolder:
的返回值,以使用选项2一致地重现。它在使用单个NSString
时总是通过,但在使用NSFileManager
内容时总是失败。
https://www.dropbox.com/s/lqj5r5ndg0qusak/Spark.zip
在展开根“文件”项目后立即发生崩溃。
答案 0 :(得分:1)
直接从文件系统提供大纲视图内容可能有点不安全,例如,如果从文件系统添加/删除文件会发生什么?更好的方法是缓存文件系统内容并直接从中提供内容。然后,您可以确保从以下位置返回值:
– numberOfRowsInTableView:
匹配您存储的内容(并且在请求不再存在的行时不会出现越界异常。)
非常想要你可以观察文件系统并刷新缓存,然后在对其进行更改时大纲视图。
更新:除此之外,作为缓存的一部分,您通常使用如下数据结构在大纲视图中构建节点树:
@interface OutlineNode : NSObject
{
id _item;
OutlineNode * __weak _parentNode;
NSMutableArray *_childNodes;
}
您可以在OutlineView中设置特定节点,例如:
- (BOOL)outlineView:(NSOutlineView *)outlineView
isItemExpandable:(id)item
{
if (item == nil)
return YES;
OutlineNode *node = (OutlineNode *)item;
return node.parentNode == nil;
}