4

I have a custom CCNode class that has a bunch of children nodes, and I want to keep references to the children in order to make some custom transitions.

For instance for the child background the custom class would look like this:

@interface MyNode : CCNode
@property (nonatomic, strong) CCNode *background;
@end

@implementation
- (void)setBackground:(CCNode *)background {
    if (_background) {
        [self removeChild:_background];
    }
    if (background) {
        [self addChild:background];
    }
    _background = background;
}
- (void)runTransition {
    if (_background)
        [_background runAction:[…]];
}
@end

The problem is that this causes a retain cycle on ARC with the node background never being freed from memory.

Bas
  • 4,423
  • 8
  • 36
  • 53
rraallvv
  • 2,875
  • 6
  • 30
  • 67

2 Answers2

1

There are no hard rules for memory management. You need to look at your code and decide the best method to use.

In your case though as you only ever have one background you could just make that property weak. Cocos2d holds a strong reference to all nodes that are in the scene graph so it will hold onto it for you.

This doesn't mean that every node should be stored as weak, sometimes you want the node to hang around if its not in the scene graph.

Ben Trengrove
  • 8,191
  • 3
  • 40
  • 58
1

Change your interface to use a zeroing weak reference:

@interface MyNode : CCNode
@property (nonatomic, weak) CCNode *background;
@end

If the background node deallocates, the _background ivar will become nil automatically. That way you won't have a retain cycle anymore. This is generally good practice if you store a node reference in a node that is a child or grandchild of the node because those situations will always cause a retain cycle.

Your code as is should work fine with a weak reference.

Note however that you need to be careful when creating and assigning to a weak reference, for instance this will fail with a nil node being added as child:

_background = [CCNode node];
[self addChild:_background];

The problem here is that after the assignment, there is nothing strongly holding on to the background node, so it deallocates and is set to nil before the addChild: line.

There's a simple workaround:

CCNode* bg = [CCNode node];
[self addChild:bg];
_background = bg;

After the node has been added as child, the children array will hold a strong reference to the node. So after the addChild: line you can assign the temporary bg node to the _background ivar.

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
  • It begs the question : did you need a @property in the first place, as opposed to a plain -(void) setThisAndThadNode:(CCNode*) theNode; with a __weak CCNode* _thisAndThat; declaration in the interface. – YvesLeBorg Oct 30 '14 at 14:01
  • The compiler complains saying that the weak property or instance var may be unpredictable set to nil, I know I can create a __strong local variable to hold a reference to the child node while the method is being executed, is that ok? – rraallvv Oct 30 '14 at 20:49
  • can you ask a new question for this with the offending code (plus surrounding for context) and the exact error message? Normally the compiler should not complain unless it's something like the first code fragment in my answer – CodeSmile Oct 30 '14 at 21:46
  • I've created a [new question](http://stackoverflow.com/q/26665092/1436359) explaining how changing the property to weak causes the compiler to complain and also added some context, I hope – rraallvv Oct 30 '14 at 23:22