views:

4114

answers:

3

I'm trying to keep track of my sprites in an array, add and remove them from layers, and then finally clear them out of the array.

I'm using the following code:

Sprite * Trees[50];
Layer * Forest;

Forest =  [Layer node];
Forest.isTouchEnabled = YES;
[self addChild:Forest z:30];

// do this a bunch of times
Trees[0] = [[Sprite spriteWithFile:@"mytree.png"] retain];
[Trees[0] setPosition:cpv(240,160)];
[Forest addChild:Trees[0] z:5];

And then when I want to destroy a tree I use:

[Forest removeChild:Trees[0] cleanup:YES];
[Trees[0] release];

My problem is that when I look in Instruments, I'm never reclaiming that memory, there is never a drop back down. I thought that by releasing the sprite it would free up the memory. Am I doing this completely wrong?

+1  A: 

My suspicion is that you are "over" retaining:

Trees[0] = [[Sprite spriteWithFile:@"mytree.png"] retain];

If Trees is a local variable in a function you do not have to retain in that case if spriteWithFile is returning a Sprite with an autorelease.

The section on delay release in the apple documentation discusses this further. The long and short of it is that the receiver of the autorelease is guaranteed to have the object be valid for the duration of its scope. If you need the object beyond the scope of the function (e.g. Trees is a property of a class) then yes, in that case you need a retain (or just synthesize a property configured to retain).

By issuing the extra retain, it is likely that your retain count is always too high (never reaches 0) and hence your object is not garbage collected.

For good measure, I'd suggest reviewing this paragraph as well that talks about the validity of objects.

hyuan
I believe your answer might be incorrect. There are two retains in the above code, and two corresponding releases. The error is not in Patrick's code.
EightyEight
I think it depends on how spriteWithFile works. By convention most static methods that are factories return via autorelease (at least all of Apple's API does this). If spriteWithFile returns a Sprite with autorelease called on it, he does not need to retain. I believe the retain count is always > 0 in his code which is why the memory is not freed.
hyuan
retain/release count is correct, however i would advise to use NSMutableArray so that you do not need the extra retain.
GamingHorror
A: 

Even though you call [Trees[x] release], I believe you still need to 'delete' the item from the array, like Trees[x] = nil or something, as the array itself is still containing the object.

The 'retain' in the Sprite creation is also not necessary, as [Forest addChild:z:] will place a retain on it as well (afaik).

David Higgins
Tree is an array, and therefore doesn't retain objects that it stores.. so there's no need to delete it from the array for memory to be freed.
EightyEight
Yup, which is why i would use NS(Mutable)Array in such cases.
GamingHorror
+2  A: 

I know that when you are using the simulator with cocos2d, the memory doesn't look like it's being released, so you have to run it on the device to get an accurate picture of what's going on.

There is a good discussion here about cocos2d and memory.

What I've noticed is that everything that you create and retain must be released, but it isn't released from memory until I do this:

[[TextureMgr sharedTextureMgr] removeAllTextures];

That will release the memory.

Here's a bigger example:

Sprite * sPopup = [[Sprite spriteWithFile:@"popup.png"] retain];
    sPopup.position = cpv(240,440);
    [self addChild: sPopup z:2];
[sPopup release];

Then, when I'm done with sPopup in another function I have this:

[[TextureMgr sharedTextureMgr] removeAllTextures];

and the memory is freed.

Bryan Cimo