EXC_BAD_ACCESS lors de l'utilisation NSOutlineView
-
12-09-2019 - |
Question
Je suis en train d'obtenir une vue Outline pour afficher un répertoire, maintenant j'ai édité l'exemple d'Apple pour le faire fonctionner à partir de tous les répertoires que je mis, sauf lors de l'expansion un nœud que je reçois « EXEC_BAD_ACCESS » de la classe NSOutlineView .
Voici le fichier d'en-tête:
#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
est le fichier de mise en œuvre ici:
#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
Mise à jour: mis à jour le code avec la dernière version
La solution
Vous ne gérez pas correctement la mémoire.
(1) Cette ligne de fuite de code. AutoRelease l'instance SMLDirectoryDataItem.
return (item == nil) ? [[SMLDirectoryDataItem alloc] initWithPath:rootDirectory parent:nil] : [item childAtIndex:index];
(2) Dans votre -initWithPath: parent: méthode, la ligne de code suivante ne conserve pas la chaîne. La piscine autorelease libère égoutté. Cela conduit très probablement à votre accident:
relativePath = [path lastPathComponent];
Donnez votre avis sur ceci:
http://developer.apple.com /mac/library/DOCUMENTATION/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
Il y a quelques problèmes supplémentaires dans le code (le code mis à jour):
(1) D'abord et avant tout, ce ...
#define IsALeafNode ((id)-1)
.... est complètement faux. Vous passez -1 dans les choses qui attendent des objets. plantage immédiat si quelque chose conserve / autoreleases ou autres messages.
(2) En outre, vous n'êtes toujours pas correctement la mémoire gérez. Votre -setRootDirectory: méthode ne conserve pas la chaîne. Je suggère d'utiliser un @property et @synthesizing le setter / getter.
(3) Votre méthode -enfants coule des chaînes comme un tamis. Plus précisément, est erroné de l'utilisation de la variable de nom de fichier.