Question

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
Was it helpful?

Solution

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.

OTHER TIPS

Don't retain your CCLayer in the button. This will prevent it from leaking in the described situation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top