views:

69

answers:

4

Hi there,
When I analyze the following code with Instruments, it reports a leak on variable imageName:

//loadImagesFromPotatoesIndexesArray
-(void) loadImagesFromPotatoesIndexesArray{

    //Load Textures from Disk
    textures = [[NSMutableArray alloc] init];
    //NSArray *masks = [[NSArray alloc] initWithArray:mainDelegate.masksArray];

    for (int i = 0;i<[potatoesIndexesArray count];i++){ 

        int imageNumber = [[potatoesIndexesArray objectAtIndex:i]intValue];

        NSString *imageName = [[NSString alloc] initWithFormat:@"texture%d",imageNumber];

        UIImage *image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:imageName ofType:@"png"]];

        NSArray *pics = [[NSArray alloc] initWithObjects:
                         [self maskImage:image withMask:[mainDelegate.masksArray objectAtIndex:i]],
                         [self maskImage:image withMask:[mainDelegate.masksArray objectAtIndex:i]],
                         imageName, 
                         nil]; 

        [textures addObject:pics];

        [image release];
        [imageName release];
        [pics release];
    }
}

[potatoesIndexesArray count] = 16, so I've got 16 times that NSCFString leaking ... But to me the code is respecting memory management ... obviously not!!! What did I do wrong?

A: 

If think that when you add imageName in your pics array it retain it ;-) (I think it answer to your question)

But, why are you doing a alloc here ? why not doing something like

[ NSString stringWithFormat:@"" ]
?

Good Luck !

Vinzius
Yup, if you add something to an array it will be retained. That is not the same as leaking though, as you can still access it via the array.
Johan Kool
+stringWithFormat is going to add to the autorelease pool. Using -initWithFormat means the string can be released well before the autorelease pool gets drained, saving memory. I have no idea if that is critical to this bit of code or not, but there's the reason to use -init... over +string...
Graham Perks
A: 

This is a complicated issue. You alloc the imageName, so the retainCount is 1, then you add it into an array, the retain count is 2, when you release the imageName, the retain Count is 1 again. Then if you also release the pics array, everything will be fine. But your pics array is added into textures, then the pics is released, so your pics retainCount is still 1. And your imageName is leaked. But, if you release the textures array, everything will be fine

    NSString *imageName = [[NSString alloc] initWithFormat:@"texture%d",imageNumber];

   NSArray *pics = [[NSArray alloc] initWithObjects:
                     [self maskImage:image withMask:[mainDelegate.masksArray objectAtIndex:i]],
                     [self maskImage:image withMask:[mainDelegate.masksArray objectAtIndex:i]],
                     imageName, 
                     nil]; 

    [imageName release];
vodkhang
I'll have to assume he deals with releasing the textures array properly after using it. Your explanation is off, and not why he sees the leak.
Johan Kool
Sounds like a reasonable (and correct) explanation to me.
Graham Perks
The root problem is probably not releasing the textures array. If the textures array is released, everything it contains will be released (including the pics array, which will release imageName).
Josh Hinman
yeah, I should explain carefully that part
vodkhang
+3  A: 

You never release the 'textures' array. It's still holding everything.

Graham Perks
+1  A: 

How often is loadImagesFromPotatoesIndexesArray called in your code? If is called more than once, all of the values in the original array will be leaked, since you don't properly release textures before replacing it with a new array.

If it is being called more than once, this should do the trick:

// load textures from disk
[textures removeAllObjects];
//NSArray *masks = [[NSArray ...

for (int i=0; ...
e.James