I have three classes, let's call them A,B and C. Class A has a CCLayer class added called B. B has a CCLayer child added too, called C. Now, C plays a sound effect that I would like to stop when scene A is replaced. I assumed that if scene A is replaced by calling -replaceScene, all its children are being removed and cleaned up as well. So I tried to put my piece of code that should stop the sound into the -onExit method of class C. However -onExit is never called on any of the children of the replaced scene. Why is that, and how can I solve this ?
All the methods (stopping the sound etc.) work, I just don't know where to call them. The situation is basically the following: I am in my main scene and if I tap the "main menu" button, I want its children to stop playing any sounds. How do the children know their parent is being released ?
If onExit isn't called for a node it means that it wasn't removed from the scene hierarchy. This points to a memory leak, specifically a retain cycle. You can confirm this by setting a breakpoint in the CCScene's dealloc method. If it doesn't get hit when changing scenes, you're leaking the scene.
Related
When exactly is the dealloc method of a Cocos2D scene called?
Right when another scene is loaded? Or after the scene has finished loading?
Additionally, what must be in the dealloc method if I plan on overwriting it?
Apparently, cocos2D automatically removes all nodes attached to a scene when the scene is deallocated. However, if I plan on overwriting it, specifically what methods must I call?
So how can I manage my scene to make sure they are leak free, 100%?
Thanks in advance!
CCScene's deallocator follows the same rules as any other object's. It will run when the reference count to CCScene reaches zero.
A scene by default doesn't care about another which is about to replace it, but if you're changing scene with a transition, there will be a period of time when two scenes exist at the same time. When the transition ends, the transition will release its reference to the first scene, which will probably be the last such reference, and the first scene will then be deallocated.
In your scene deallocator, put a CCLOG to see exactly when it's run. I put one in each to make sure.
In general, manually release any object which you created using a method starting with alloc, new or copy, whether or not it's a Cocos2D object or otherwise. Other creation methods, such as Cocos2D's node, do not require a manual release, unless you have chosen to retain the object manually yourself as well, which might be advisable if you are not going to add it as a child to another node straight away.
As you have said, adding a node as a child to another does not mean it needs an extra release; Cocos2D will handle that one.
Every object you allocate in your scene class which is not added to the scene as a child must be released explicitly.
A scene is released (and most of the times deallocated if you have not retained it somewhere else) when you replace it (with the replaceScene method)with another scene object or pop it from the scenes stack.
It is always advisable to look in the source code (which contains very helpful comments) and learn what exactly should be done if you customize your scene class.
I have a viewcontroller with four (4) AVPlayers (with AVPlayerLayers like APPLE example).
If I pop this viewcontroller and the push a new instance of the same type. I'm not able to play video in one or two AVPlayers. No errors and code runs fine, AVPlayerLayers also says it has a superLayer.
And to the most strange thing if I push home button, coming back to springboard and the enter the app all video players like magic start playing. It's like it rerender the view tree or something.
Any hints or clues?
PS. I wait for assets to be ready using loadValuesAsynchronouslyForKeys.
We had a similar problem. Following answer lead to the solution:
AVplayer not showing in ScrollView after 2-3 times
You have to call: [AVPlayer replaceCurrentItemWithPlayerItem:nil]; when your viewcontroller gets unloaded. This might be tricky as you might have added an observer or used addBoundaryTimeObserverForTimes:queue:usingBlock:
Also you have to be careful when checking agaings superlayer: Better check against uiview.window when determing whether your view is still attached to the view hierarchy.
yours
phil
I have a bunch of classes that retain an instance of the scene and I'm starting to think this is going to cause memory management issues for me.
So I have Scene1, Scene2 and a HelperClass that has a property that retains the scene.
When I switch from Scene1 to Scene2 I want everything to be disposed.
I started thinking though am I going to have to manually release the helper class before I call the director to change the scene?
The helper class is retained by a layer that is a child of the scene.
The layer also has a property reference to the scene as a ccnode.
Am I doing this wrong? What is the best way to arrange these things so the memory gets free correctly.
The helper classes do things like creating bullets and adding them to the scene.
I have a similar setup with CCSprites that only exist at the scene level. I keep references to them in the helper classes.
once you add something to a container, a scene or spritesheet or whatever, release it, the container keeps a ref to it, then when you dispose of the container, it will be released.
Scene will not be released if you call push scene, only if you run a new one or call the replaceScene method of CCDirector.
I have a cocos2d hierarchy of layers that is very very deep. I want to access my scene from any of the layers? How would I do this?
If I use a singleton will the retain on the singleton prevent the layer from being garbage collected when scenes are changed using the director?
i guess one approch is to use [CCDirector sharedDirector].runningScene sould do the trick if you want to get access to the current running scene, but about decleraing your scene as a singleton yes it prevents garbage collector if you retain your scene whenever iit's created but you have to remeber to release it whenever you are done with your scene.
I have an odd problem with UIImagePickerControllerSourceTypeCamera. My application gives the choice to select a pic from the gallery, or take a photo with the camera. If I choose the gallery, I pick a photo and return to my view, no issues.
However, when using UIImagePickerControllerSourceTypeCamera, it appears to do something odd with my view when I return to it.
For example, I have a bunch of code in the viewDidLoad method which moves some objects in the view if it needs to based on some factors - this code gets called when I exit the UIImagePickerControllerSourceTypeCamera, but doesnt get called when I exit the gallery.
Is this expected?
I think your view is getting dumped by the didReceiveMemoryWarning thing which is being triggered by the resource-intensive camera stuff. You can force the simulator to generate a memory warning without the camera to test this theory.
Generally speaking, viewDidLoad needs to be able to deal with getting called multiple times. It's not an init method. It gets called again if self.view gets set to nil and the view later needs to be recreated. There may be a more appropriate place to put any code you have there that's causing problems, but the init methods are tricky because the designated initializer is bypassed by nib loading.
When loaded from a nib, the class's initWithCoder is called instead which bypasses the whole init process because dearchiving is assumed to be sucking in an already-initialized object. Therefore reinitializing the object might break stuff, like call loadView which essentially conflicts with what a nib contains as it's supposed to programmatically construct what the nib already has in it. You can still override initWithCoder as usual though as long as you pass through the args to super like you should, but then this will not get called if you initialize the object with the designated initializer. Of course if you need to worry about that you can put all the code you want executed in both into a method that gets called from both overridden methods.