2009-09-20 80 views
2

我试图得到一个大纲视图来显示一个目录,现在我编辑了从苹果的例子,使其工作从我设置的任何目录,除了扩展任何节点时,我得到“EXEC_BAD_ACCESS”来自NSOutlineView类。EXC_BAD_ACCESS当使用NSOutlineView

这里是头文件:

#import <Cocoa/Cocoa.h> 

@interface SMLDirectoryDataSource : NSObject { 
    NSString *rootDirectory; 
} 

- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item; 
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item; 
- (id)outlineView:(NSOutlineView *)outlineView 
      child:(int)index 
      ofItem:(id)item; 
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn 
      byItem:(id)item; 
- (void) setRootDirectory:(NSString *)directory; 

@end 

@interface SMLDirectoryDataItem : NSObject 
{ 
    NSString *relativePath, *fullPath; 
    SMLDirectoryDataItem *parent; 
    NSMutableArray *children; 
} 

//+ (SMLDirectoryDataItem *)rootItem; 
- (int)numberOfChildren;// Returns -1 for leaf nodes 
- (SMLDirectoryDataItem *)childAtIndex:(int)n;// Invalid to call on leaf nodes 
- (NSString *)fullPath; 
- (NSString *)relativePath; 

@end 

这里是实现文件:

#import "SMLDirectoryDataSource.h" 


@implementation SMLDirectoryDataSource 
- (id)initWithDirectory:(NSString *)path 
{ 
    rootDirectory = path; 
    return self; 
} 

- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item 
{ 
    return (item == nil) ? 1 : [item numberOfChildren]; 
} 

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item 
{ 
    return (item == nil) ? NO : ([item numberOfChildren] != -1); 
} 

- (id)outlineView:(NSOutlineView *)outlineView 
      child:(int)index 
      ofItem:(id)item 
{ 
    NSLog(@"hi there"); 
    if(rootDirectory == nil) 
      rootDirectory = @"/"; 
    NSLog(rootDirectory); 
    if(item == nil){ 
     SMLDirectoryDataItem *item = [[SMLDirectoryDataItem alloc] initWithPath:rootDirectory parent:NULL]; 
     return item; 
     [item release]; 
    } 
    else 
     return [(SMLDirectoryDataItem *)item childAtIndex:index]; 
} 
/*(
- (id)outlineView:(NSOutlineView *)outlineView 
objectValueForTableColumn:(NSTableColumn *)tableColumn 
      byItem:(id)item 
{ 
    if(rootDirectory == nil) 
     rootDirectory = @"/"; 
    return rootDirectory; 
} 
*/ 
- (void)setRootDirectory:(NSString *)directory 
{ 
    rootDirectory = directory; 
} 

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { 
    if(item == nil) 
     return rootDirectory; 
    else 
     return (id)[(SMLDirectoryDataItem *)item relativePath]; 
} 

- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item { 
    return NO; 
} 

@end 

@implementation SMLDirectoryDataItem 

//static SMLDirectoryDataItem *rootItem = nil; 
#define IsALeafNode ((id)-1) 

- (id)initWithPath:(NSString *)path parent:(SMLDirectoryDataItem *)obj 
{ 
    fullPath = [path copy]; 
    if (self = [super init]) 
    { 
     relativePath = [[path lastPathComponent] copy]; 
     parent = obj; 
    } 
    return self; 
} 


/*+ (SMLDirectoryDataItem *)rootItem 
{ 
    if (rootItem == nil) rootItem = [[SMLDirectoryDataItem alloc] initWithPath:@"/" parent:nil]; 
    return rootItem; 
}*/ 


// Creates, caches, and returns the array of children 
// Loads children incrementally 
- (NSArray *)children 
{ 
    if (children == NULL) { 
     NSFileManager *fileManager = [NSFileManager defaultManager]; 
     //NSString *fullPath = [self fullPath]; 
     BOOL isDir, valid = [fileManager fileExistsAtPath:fullPath isDirectory:&isDir]; 
     if (valid && isDir) { 
      NSArray *array = [fileManager contentsOfDirectoryAtPath:fullPath error:NULL]; 
      if (!array) { // This is unexpected 
       children = [[NSMutableArray alloc] init]; 
      } else { 
       NSInteger cnt, numChildren = [array count]; 
       children = [[NSMutableArray alloc] initWithCapacity:numChildren]; 
       NSString *filename = [[NSString alloc] init]; 
       for (cnt = 0; cnt < numChildren; cnt++) { 
        filename = [fullPath stringByAppendingPathComponent:[array objectAtIndex:cnt]]; 
        SMLDirectoryDataItem *item = [[SMLDirectoryDataItem alloc] initWithPath:filename parent:self]; 
        [children addObject:item]; 
        [item release]; 
       } 
       [filename release]; 
      } 
     } else { 
      NSLog(@"is a leaf... strange"); 
      children = IsALeafNode; 
     } 
    } 
    return children; 
} 


- (NSString *)relativePath 
{ 
    return relativePath; 
} 


- (NSString *)fullPath 
{ 
    // If no parent, return our own relative path 
    //if (parent == nil) return relativePath; 

    // recurse up the hierarchy, prepending each parent’s path 
    //return [[parent fullPath] stringByAppendingPathComponent:relativePath]; 
    return fullPath; 
} 

- (SMLDirectoryDataItem *)childAtIndex:(int)n 
{ 
    return [[self children] objectAtIndex:n]; 
} 

- (int)numberOfChildren 
{ 
    id tmp = [self children]; 
    return (tmp == IsALeafNode) ? (0) : [tmp count]; 
} 


- (void)dealloc 
{ 
    if (children != IsALeafNode) [children release]; 
    [relativePath release]; 
    [super dealloc]; 
} 

@end 

更新:更新了最新版本的代码

回答

7

你是不是正确管理内存。

(1)这行代码泄漏。自动释放SMLDirectoryDataItem实例。

return (item == nil) ? [[SMLDirectoryDataItem alloc] initWithPath:rootDirectory parent:nil] : [item childAtIndex:index]; 

(2)在您的-initWithPath:parent:方法中,以下代码行不保留字符串。自动释放池在耗尽时释放它。这是最有可能导致您的崩溃:

relativePath = [path lastPathComponent]; 

评论此:

http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

有代码(更新后的代码)的一些其他问题:

(1)第一最重要的是,这...

#define IsALeafNode ((id)-1) 

.... is complet是错的。你将-1传递给期望对象的东西。如果有任何保留/自动发布或其他消息,则立即崩溃。

(2)此外,您仍然没有正确管理内存。您的-setRootDirectory:方法不保留该字符串。我会建议使用@property和@snthesizing setter/getter。

(3)你的-children方法像筛子一样漏出字符串。具体来说,文件名变量的用法是错误的。

+0

好,所以我改变了它,所以它不会崩溃,但现在它说“[__NSCFType numberOfChildren]:无法识别的选择器发送到实例” – kennyisaheadbanger 2009-09-20 18:32:29

+0

然后,你将不得不做一些调试。打破-outlineView:numberOfChildrenOfItem:并查看项目的价值和等级。然后确定项目的类别是如何成为它的。 – 2009-09-20 21:37:36

+0

现在我真的很困惑..我已经复制了更新的示例中的东西,现在的方法objectValueForTableColumn正在使它崩溃,即使它被调用大约4次事先和经营好吧... if(item == nil )由于某种原因不工作! – kennyisaheadbanger 2009-09-22 12:52:48