Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Aranince

macrumors 65816
Original poster
Apr 18, 2007
1,104
0
California
I'm trying to write a text editor, and I'm working on getting the source list to work(similar to Coda and TextMate). When I open a reletivly small directory, my app works fine. However, when I open a bigger directory, the app crashes saying that it has run out of memory and is unsafe to call malloc.

Basically what the App is doing right now is populating an NSOutlineView with the files and directories of a directory that the user chooses.

Code:
- (void)populateSourceListView {
	NSFileManager *fileManager = [NSFileManager defaultManager];
	
	BOOL isDir, valid;
	
	valid = [fileManager fileExistsAtPath:path isDirectory:&isDir];
	
	if(valid && isDir) {
		
		SourceListItem *rootItem = [[SourceListItem alloc] init];
		[rootItem setTitle:[path lastPathComponent]];
		
		NSArray *files = [fileManager contentsOfDirectoryAtPath:path error:nil];
		
		for(int i = 0; i < [files count]; i++) {
			
			NSString *file = [files objectAtIndex:i];
			// If we are a directory
			NSMutableString *newPath = [[NSMutableString alloc] init];
			[newPath stringByAppendingFormat:@"%@/%@",path,file];
			
			if ([fileManager fileExistsAtPath:newPath isDirectory:&isDir] && isDir == YES) {
				SourceListItem *newNode = [[SourceListItem alloc] init];
				[self populateItem:newNode atPath:newPath];
				[newNode setTitle:file];
				[rootItem addChild:newNode];
				[newNode release];
			} else {
				SourceListItem *newNode = [[SourceListItem alloc] initLeaf];
				[newNode setTitle:file];
				[rootItem addChild:newNode];
				[newNode release];
			}
			
			[newPath release];
			
		}
		
		[sourceListContents addObject:rootItem];
		[rootItem release];
		[files release];
	}
	
}

- (void)populateItem:(SourceListItem*)item atPath:(NSString*)p {
	if ([item leaf] == YES) {
		return;
	}
		 
	NSFileManager *fileManager = [NSFileManager defaultManager];
		 
	NSArray *items = [fileManager contentsOfDirectoryAtPath:p error:nil];
		 
	for (int i = 0; i < [items count]; i++) {
		BOOL isDir;
		NSString *file = [items objectAtIndex:i];
		NSMutableString *newPath = [[NSMutableString alloc] init];
		[newPath stringByAppendingFormat:@"%@/%@",p,file];
		// If we are a directory
		
		if ([fileManager fileExistsAtPath:newPath isDirectory:&isDir] && isDir == YES) {
			SourceListItem *newNode = [[SourceListItem alloc] init];
			[self populateItem:newNode atPath:newPath];
			[newNode setTitle:file];
			[item addChild:newNode];
			[newNode release];
		} else {
			SourceListItem *newNode = [[SourceListItem alloc] initLeaf];
			[newNode setTitle:file];
			[item addChild:newNode];
			[newNode release];
		}
		
		[newPath release];
		
	}
	
	[items release];
}
 
I'm trying to write a text editor, and I'm working on getting the source list to work(similar to Coda and TextMate). When I open a reletivly small directory, my app works fine. However, when I open a bigger directory, the app crashes saying that it has run out of memory and is unsafe to call malloc.

Basically what the App is doing right now is populating an NSOutlineView with the files and directories of a directory that the user chooses.

Code:
- (void)populateSourceListView {
	NSFileManager *fileManager = [NSFileManager defaultManager];
	
	BOOL isDir, valid;
	
	valid = [fileManager fileExistsAtPath:path isDirectory:&isDir];
	
	if(valid && isDir) {
		
		SourceListItem *rootItem = [[SourceListItem alloc] init];
		[rootItem setTitle:[path lastPathComponent]];
		
		NSArray *files = [fileManager contentsOfDirectoryAtPath:path error:nil];
		
		for(int i = 0; i < [files count]; i++) {
			
			NSString *file = [files objectAtIndex:i];
			// If we are a directory
			NSMutableString *newPath = [[NSMutableString alloc] init];
			[newPath stringByAppendingFormat:@"%@/%@",path,file];
			
			if ([fileManager fileExistsAtPath:newPath isDirectory:&isDir] && isDir == YES) {
				SourceListItem *newNode = [[SourceListItem alloc] init];
				[self populateItem:newNode atPath:newPath];
				[newNode setTitle:file];
				[rootItem addChild:newNode];
				[newNode release];
			} else {
				SourceListItem *newNode = [[SourceListItem alloc] initLeaf];
				[newNode setTitle:file];
				[rootItem addChild:newNode];
				[newNode release];
			}
			
			[newPath release];
			
		}
		
		[sourceListContents addObject:rootItem];
		[rootItem release];
		[files release];
	}
	
}

- (void)populateItem:(SourceListItem*)item atPath:(NSString*)p {
	if ([item leaf] == YES) {
		return;
	}
		 
	NSFileManager *fileManager = [NSFileManager defaultManager];
		 
	NSArray *items = [fileManager contentsOfDirectoryAtPath:p error:nil];
		 
	for (int i = 0; i < [items count]; i++) {
		BOOL isDir;
		NSString *file = [items objectAtIndex:i];
		NSMutableString *newPath = [[NSMutableString alloc] init];
		[newPath stringByAppendingFormat:@"%@/%@",p,file];
		// If we are a directory
		
		if ([fileManager fileExistsAtPath:newPath isDirectory:&isDir] && isDir == YES) {
			SourceListItem *newNode = [[SourceListItem alloc] init];
			[self populateItem:newNode atPath:newPath];
			[newNode setTitle:file];
			[item addChild:newNode];
			[newNode release];
		} else {
			SourceListItem *newNode = [[SourceListItem alloc] initLeaf];
			[newNode setTitle:file];
			[item addChild:newNode];
			[newNode release];
		}
		
		[newPath release];
		
	}
	
	[items release];
}

Get Xcode and use instruments, or when running the program. Open a terminal and run "top" without the quotes. This might help show if its using too much ram or its a bug in the code.
 
If you're not actually leaking memory, then another thing to consider is an autorelease pool inside the loop so you don't build up autoreleased objects.
 
Post the source for SourceListItem.


Code:
NSMutableString *newPath = [[NSMutableString alloc] init];
[newPath stringByAppendingFormat:@"%@/%@",p,file];
This code is wrong (in both places).

Use the NSMutableString method, appendFormat: . It will mutate the existing object.

Or use the NSString method +format: instead. It will return an autoreleased string, so deal with it accordingly.


Code:
   [files release];
}

...
   [items release];
}
This code is wrong (in two places, with different variable names).

You don't own the NSArray object at that point.


Your factoring is horrible. Don't copy and paste code that's exactly the same. There should be only one place that performs the recursive descent, not two. You're making it twice as hard to debug.
 
Yea I was too cought up In trying to understand and get the dang thing to work. I'll try your suggestions....thanks
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.