2009-09-20 3 views
2

디렉토리를 표시하기 위해 아웃 라인보기를 얻으려고하고 있습니다. 이제는 "EXEC_BAD_ACCESS"노드를 확장 할 때를 제외하고 내가 설정 한 모든 디렉토리에서 작동하도록 Apple의 예제를 편집했습니다. NSOutlineView 클래스에서. 여기 NSOutlineView를 사용할 때 EXC_BAD_ACCESS

헤더 파일입니다

#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) 다음 코드 줄은 문자열을 유지하지 않습니다. 자동 풀 풀은 배수가되었을 때 풀어 놓습니다. 이것은 대부분의 가능성이 충돌을 선도하고 있습니다 :

relativePath = [path lastPathComponent]; 

검토이 :

(1) 첫째 : 코드 (업데이트 된 코드)에 몇 가지 추가적인 문제가 있습니다

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

그리고 무엇보다도이 ...

#define IsALeafNode ((id)-1) 

가 완료됩니다. 틀린. 당신은 -1을 객체를 기대하는 것으로 통과시킵니다. 어떤 것이나/자동 반복 또는 기타 메시지를 남기면 즉시 충돌합니다.

(2) 또한 메모리를 올바르게 관리하지 못합니다. 귀하의 -setRootDirectory : 메서드는 문자열을 유지하지 않습니다. @property를 사용하고 setter/getter를 @synthesizing하는 것이 좋습니다.

(3) 여러분의 자녀가 체와 같은 끈을 새고 있습니다. 특히 파일 이름 변수의 사용법이 잘못되었습니다.

+0

괜찮 았으므로 충돌이 발생하지 않도록 변경했지만 이제는 "[__NSCFType numberOfChildren] : 인식 할 수없는 선택기를 인스턴스로 보냄" – kennyisaheadbanger

+0

그러면 디버깅을해야 할 것입니다. Break on -outlineView : numberOfChildrenOfItem : 항목의 값과 클래스가 무엇인지 확인합니다. 그런 다음 아이템 클래스가 어떻게 생겼는지 결정하십시오. –

+0

이제 저는 정말로 혼란 스럽습니다. 업데이트 된 예제를 복사했습니다. 그리고 objectValueForTableColumn 메서드는 충돌을 일으키고 있습니다. 사전에 약 4 번 호출하여 작동하고 있지만 ... if (item == nil) 어떤 이유로 작동하지 않습니다! – kennyisaheadbanger