First of all: retainCount
is useless.
This here returns an autoreleased instance of MyLayer:
_myLayer = [MyLayer node];
It is the equivalent of:
_myLayer = [[[MyLayer alloc] init] autorelease];
If you were to leave it at that with no other code, the _myLayer
would become a dangling pointer some time after the init method returns. Definitely the next time the autorelease pool is purged, which if I remember correctly happens ever frame in cocos2d. Under ARC, the ivar by itself defaults to being a strong reference, so the layer would be retained and would not deallocate as you would expect. So if you don't like autorelease and how it behaves, use ARC. ;)
Then you add the layer as child, which puts it in an array, which means this retains the layer:
[self addChild:_myLayer];
So as long as the layer remains a child of the scene, it will not deallocate.
And now, like so many before you, you were looking at the wrong place to fix the problem of the layer not releasing. By doing this in dealloc you add an extraneous release:
[_myLayer release];
Now this works fine for the moment because the actual problem is the layer not releasing, and you force it to be released here. However some time later the scene's children array will be released, which sends release to each object, which then causes the crash due to over-releasing the layer.
Hence the actual problem that you should be tracking down is why the layer doesn't deallocate. And here I sense more problems:
I can release the whole scene
If by that you mean you were sending the release
message to the scene, then that's wrong. And again this would over-release the scene. Cocos2d will clean out the scene when you call replaceScene or similar methods. The scene itself is typically autoreleased as well, definitely when created through the node
or scene
class methods.
If that's not what you're doing and the layer doesn't release, then check if maybe you have a retain cycle. Or perhaps you're simply expecting the layers to deallocate before the scene? That doesn't necessarily have to be in this order, with autorelease no less.
You can easily create a retain cycle by having two (or more) sibling nodes holding on to each other (ie layer A retains layer B and layer B retains layer A) or by a sibling retaining its parent, for example _myLayer holding a retained reference to the scene (which btw is the same as accessing it via self.parent).
Now I'm saying to use ARC because it makes all those problems go away almost instantly, except for retain cycles. But for retain cycles it provides a very simple and effective cure: zeroing weak references.
For example you could declare the layer reference as weak in the interface and no longer worry about it retaining the layer:
__weak MyLayer *_myLayer;
Moreover when the layer is released, _myLayer will automatically be set to nil. And this happens the instance the layer has no more strong references, not at some later time as is the case with autorelease
.
The positive side effect is that you can now safely do the following:
@interface LayerA : CCLayer
@property (weak) LayerB* layerB;
@end
@interface LayerB : CCLayer
@property (weak) LayerA* layerA;
@end
Under MRC this would create a retain cycle if you assign the layers accordingly and don't set them to nil before the dealloc method. The tricky thing about retain cycles is that they can not be resolved within the dealloc method since by definition all objects participating in a retain cycle won't be deallocating. A typical place to do so in cocos2d is the cleanup method.
But now with ARC there is absolutely no problem. Either or both layers will deallocate because the reference in the other layer is not retaining (weak) and when either of the layers is deallocated the reference is set to nil, so there won't be any crashes.
I have been developing exclusively with ARC for two years. I never looked back. My quota of errors relating to memory management went down to almost zero, it's ridiculous. About the only thing I occasionally have to look into is when a weak reference is nil when I don't expect it to be. Usually that's when I incorrectly assume the object has a strong reference somewhere, but doesn't.
Using ARC is such a huge timesaver that even if you really really really really absolutely badly want to learn this, you better be really really really really almost exclusively interested in how memory management used to work back in the old days of Objective-C development. You know, like when my grandma was still writing code for the very first iPhone! :)
PS: it's a myth that you give up control over memory management when using ARC. There's a lot of neat tricks you can do to gain control back, even for a short time. Mainly by using bridge casting. So even if ARC can take a couple more cycles and that may add up in a tight loop, you can still hand-optimize the code (if you have to; you'll probably never ever have to) with MRC. This is beyond the scope of this answer (I already went too far) but these options do exist, but one hardly ever needs to exercise them.
This is why I'm brash about using ARC because not doing so is borderline irresponsible. IMO.