I've got a CCLayer where I want to add many buttons. I created the class MyButton with this init function:
-(id) initWithLayer:(MyLayer *)theLayer andDictionary:(NSDictionary *)data {
self = [super init];
if (self != nil)
{
self.layer = theLayer;
self.tag = [[data objectForKey:@"day"] intValue];
_layerZ = [[data objectForKey:@"z"] intValue];
_closedCard = [[CCSprite alloc] initWithFile:[data objectForKey:@"file"]];
_openedCardFile = [[NSString alloc] initWithString:[data objectForKey:@"open_card"]];
CCMenuItemImage *itemImage = [CCMenuItemImage
itemFromNormalSprite:_closedCard
selectedSprite:nil
target:self
selector:@selector(displayCard:)];
CGPoint position = CGPointFromString([data objectForKey:@"position"]);
_position = ccp(position.x, position.y);
itemImage.position = _position;
itemImage.tag = self.tag;
_theCardButton = [CCMenu menuWithItems:itemImage, nil];
_theCardButton.position = CGPointZero;
[self.layer addChild:_theCardButton z:_layerZ];
}
return self;
}
This init function will add the buttons to the layer and I'm managing all the behaviour (movements, image changes) in the MyButton class.
So the layer is being sent to all the MyButton instances. The layer won't call the dealloc method until each button is released.
These buttons are being added to the layer through an array:
_buttons = [[NSMutableArray alloc] init];
for (NSDictionary *buttonData in buttonsArray) {
MyButton *btn = [[MyButton alloc] initWithLayer:self andDictionary:buttonData];
[_buttons addObject:btn];
[btn release];
}
My problem is that when I replace this scene, the dealloc methos of MyButton is not being called and the memory is not being released, cause the [_buttons release] is in the dealloc method of the layer, which is not being called either, cause the layer has been passed to each button.
It's a mess. Can anyone tell me the best way for fixing this memory problem?
-- edit
If I try to release the array of buttons manually before calling the replaceScene, each button calls the dealloc, but then I get this error message:
[CCMenu pauseSchedulerAndActions]: message sent to deallocated instance 0x131a0670
Do you retain the layer in your initWithLayer:andDictionary:
method? Then you have a retain cycle.
When you send retain
message to an object, you increase its retain count by 1. When you send release
message, you decrease retain count by 1. dealloc
message is sent to object when its retain count reaches 0.
When release
message is sent to your layer, its retain count does not reach 0, because every one of _buttons
retained it for itself. Because layer's retain count never reaches 0, its dealloc
is never called and buttons never get a release message, never get their dealloc
called, never release the layer and so on. Cycle.
To avoid retain cycles, a child object must never retain any of its parents, or any of parents' parents.