It’s been a long time since my last post, but I’ve been really busy with the release of my first iPhone app: BibleMemoryFlashCards (yes, I know it’s a long name, but the original one was already taken) and then I’ve been working with my second app which I hope to release soon.
While testing and profiling my current project I found a leak that was causing me some problems because I didn’t know when to release memory. The problem basically happened in a function that returned an array of NSIntegers created using malloc().
-(NSInteger *)generateBoard:(NSString *)aSequence {
NSArray *tokens = [aSequence componentsSeparatedByString:@"/"];
NSInteger tempBoard[SSMAX_BOARD_INDEX];
NSInteger i = -1;
// Convert the array of strings to a simple array of numbers
for (NSString *token in tokens) {
tempBoard[++i] = [token intValue];
}
NSInteger *boardRef = malloc(sizeof(tempBoard));
memcpy(boardRef, tempBoard, sizeof(tempBoard));
return boardRef;
}
The Static Analyzer indicated me there was a memory leak in this line:
NSInteger *boardRef = malloc(sizeof(tempBoard));
Now, most of the answers I found in Google just mentioned that any call to malloc() should be balanced with a corresponding call to free(), so the previously allocated memory could be safely released, thus avoiding the impending memory leak.
I was wondering what could be the proper place to free memory, since I couldn’t do it within the same function where I allocated memory for my array, because I returned the pointer to the calling method. In the end I released memory in three different places:
- In the setter method used to store the pointer.
- In the
dealloc()method of the class to which the instance variable belongs. - In an external call to the
generateBoard:method.
1. The setter method ended up looking like this:
-(void)setWorkingBoard:(NSInteger *)aBoard {
if (workingBoard != nil) {
free(workingBoard);
}
workingBoard = aBoard;
}
This was necessary because in some places I just reassigned the pointer to new data, and consequently I was loosing the reference to the old allocated data, causing a leak.
2. dealloc() is the place where data cleanup is done, so I also called free() on the two pointers I use as instance variables in my class.
3. This was not so intuitive, but the Leaks Instrument indicated the following line was causing another memory leak:
SSShufflingArray *shufflingArray = [[SSShufflingArray alloc] initWithNSIntegerArray:[self generateBoard:self.sequence]];
The problem was that the call to [self generateBoard:self.sequence] created a pointer and there was no reference I could use to free memory, so I had to break this line in two:
NSInteger *tempBoard = [self generateBoard:self.sequence]; SSShufflingArray *shufflingArray = [[SSShufflingArray alloc] initWithNSIntegerArray:tempBoard];
Then I could use free(tempBoard); to release memory referenced by the returned pointer.
After these and a couple of other changes involving releasing objects, I checked again for memory leaks and this time Instruments didn’t report any problem.
