使用 NSOutlineView 时的 EXC_BAD_ACCESS

发布于 2024-08-05 10:37:36 字数 5364 浏览 11 评论 0原文

我正在尝试获取大纲视图来显示目录,现在我已经编辑了 Apple 的示例,使其可以在我设置的任何目录中工作,除非扩展任何节点时我从 NSOutlineView 类中获得“EXEC_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

更新: 使用最新版本更新了代码

i'm trying to get a Outline view to display a directory, now I've edited the example from Apple to make it work from any directory I set, except when expanding any node I get "EXEC_BAD_ACCESS" from the NSOutlineView class.

Here is the header file:

#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

And here is the implementation file:

#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

Update: updated the code with the latest version

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

葵雨 2024-08-12 10:37:36

您没有正确管理内存。

(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)

完全错误。您正在将 -1 传递给需要对象的事物。如果有任何保留/自动释放或其他消息,则会立即崩溃。

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

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

You aren't managing memory correctly.

(1) This line of code leaks. Autorelease the SMLDirectoryDataItem instance.

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

(2) In your -initWithPath:parent: method, the following line of code does not retain the string. The autorelease pool releases it when drained. This is most likely leading to your crash:

    relativePath = [path lastPathComponent];

Review this:

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

There are some additional problems in the code (the updated code):

(1) First and foremost, this...

#define IsALeafNode ((id)-1)

.... is completely wrong. You are passing -1 into things that expect objects. Immediate crash if anything retains/autoreleases or otherwise messages that.

(2) Also, you still aren't managing memory correctly. Your -setRootDirectory: method is not retaining the string. I would suggest using an @property and @synthesizing the setter/getter.

(3) Your -children method is leaking strings like a sieve. Specifically, the filename variable's usage is wrong.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文