3

単純なファイルブラウザを(で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すでになくなっています。これは、アイテムのライフサイクルのInstrumentsスクリーンショットです。

楽器のスクリーンショット

何が間違っているのかわかりませんretain。ARCが有効になっているため、明示的に何もできません(また、そうすべきではありません)が、子アイテムは失われています。

編集:実際のクラッシュのスタックトレース:

   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

クラッシュは、ルートの「ファイル」アイテムを展開した直後に発生します。

4

1 に答える 1

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;
}
于 2012-11-12T17:37:58.887 に答える