I am a baffled noob here. I have the following code:
var mC:mc = new mc();
I do NOT instantiate mC at all with an addChild(mC);
But, later in the code, I have a loop using onEnterFrame and in this loop I have the following trace function:
if(mC){
trace("mC is here");
}
This returns "mC is here" in the output window. HUH???
The problem is that I want to use this 'if' statement to removeChild(mC); [I will be adding it in the code later with an addChild(mC); based on certain stuff that happens] but it keeps throwing dang "ERROR child of the caller" messages even with the 'if' condition...
WHAT am I doing wrong? I did not know declaring variables would add them to the stage/display list, I thought you needed an addChild(); statement. Am I smoking something I shouldn't be?
Thanks in advance, ~Frustrated Inc.
When you new up an object it exists in memory, even if you have not added it to the stage. That is why when you check if mC exists, it returns true. You want to check if it exists on the stage. Something like:
var mc:MovieClip = new MovieClip();
mc.name = "test";
if (this.getChildByName("test") != null) {
trace("mc is on stage");
}
I have not used Flash for a long time, so I did not test this code. Hopefully it works.
Complex objects in AS3 (that means anything that is not a string or a number) have a default value of null. WHen evaluated that default value of null equals false:
var mymc:MovieClip;//that MC is NOT instantiated yet so it has a default value of null
if(mymc)
{
//mymc is null so this evaluates to false
//and this statement DOES NOT execute
Now when a complex object is instantiated and exist its value would now evaluates to true
var mymc:MovieClip = new MovieClip();//that MC IS instantiated
if(mymc)
{
//mymc exits so this evaluates to true and this statement EXECUTE
//notice that "!= null" is not necessary
Now your problem has to do with display list. A DisplayObject has a parent property that is null when that object is not added to a display list, and that property point to the parent when that object is added to a display list:
var mc:MovieClip = new MovieClip()
trace(mc.parent);//this is null
addChild(mc);
trace(mc.parent);//this is not null anymore and points to the parent
SO what you mean to do is:
if(mC.parent){//this means mC has a parent and can be removed from it
trace("mC is here");
}
In your code, you just control whether your variable is null or not.
You can use contains method on the display object you are trying to add to.
If you are adding mC to some sprite named container, you can simply check whether it exists in that container with:
if (!container.contains(mC))
container.addChild(mC);
Edit: The safer method to control whether a movieclip is on the stage is to control its stage value.
if (mC.stage) {
mC.parent.removeChild(mC); // this is how you remove, if you simply want to check existence, don't remove it
}
It has to have a stage value if you added the movieclip to the stage or a container that is added to stage.
Hope it is clearer this way.
Related
I have an issue with a function I use to delete an instance and replace it with another. Basically, it keeps the item in memory no matter what. Inside the object I have weak listeners and I null everything after it gets removed, but the function I run to check if it is still active tells me that it is (just an Event.ENTER_FRAME tracing some text, with a weak link).
Even when I removed everything from the instances I am loading, it still seems to stay in memory, according to my trace it still is. How do I completely delete something from memory more thoroughly than nulling it out after removing it from the stage? Am I not seeing something?
This is the function:
private function loadArea(inputArea:String)
{
//This is for a checker to make sure that areas only get loaded once.
currentRoom = inputArea;
//If the area currently loaded is not null, make it null now.
if(selectedArea != null) selectedArea = null;
//Null any data inside of the reference used to create the name of the new area.
areaReference = null;
//Grab the class using the input.
areaReference = getDefinitionByName(inputArea + "Area") as Class;
//Null the sprite used to house the class
areaSprite = null;
//Set the holder as a new instance of the desired class.
areaSprite = new areaReference() as Sprite;
//If the selected area is still not null for some reason,
if(selectedArea != null)
{
//Remove the area from the container...
areaContainer.removeChild(selectedArea);
//...and nullify it.
selectedArea = null;
}
//Set the current area as the newly created instance.
selectedArea = areaSprite;
//If the area is not the "Game", load in the assets one way,
if(inputArea != "Game") selectedArea.construct(areaAssets);
//otherwise do it another way.
else selectedArea.construct(newScreenData,apiServer,cdnServer,areaAssets);
//This is for a checker that fades out the screen, which it needs to fade back in soon.
newScreenData = null;
//While the container for areas has any areas inside of it, remove them.
while(areaContainer.numChildren) areaContainer.removeChildAt(0);
//...then add the new instance area to the container.
areaContainer.addChild(selectedArea);
//...then let all the parts of the game know that a new area has been laoded in.
Global.echoEvent.echo("gameBootUp","playAreaIn");
}
The memory is actually released when Garbage Collector will find and erase an orphaned instance of yours. Before that, your memory usage will state there is an instance in memory. There is no way to force garbage collection, calling System.gc() only "instructs" Flash to run it, it might not obey. So, you have done what you had to, let it be.
Removing all references including stage and nulling an object is all it takes to free up memory.
If the object is not being released then you are missing something or doing something incorrectly or out of sequence.
Carefully go through your code, making sure you identify where objects are being referenced so you can remove them.
Looking at your example code:
if(selectedArea != null) selectedArea = null;
Here you are making sure that the selectedArea is null.
But immediately after you are testing selectedArea again
(you know it is null so this block is never used)
if(selectedArea != null){
//Remove the area from the container...
areaContainer.removeChild(selectedArea);
//...and nullify it.
selectedArea = null;
}
In every language its VERY DIFFICULT to "clear" memory... even HTML. That being said... try to reduce your memory footprint.
Correct Null:
1. remove all event listeners
2. remove all children
3. remove all mapped/referenced methods/parameters
4. set the class object to null
In most cases this is all you need to do, the WAY you do it will determine if the object gets cleared. Consider the following situation.
You have a custom sprite class (MEMORY FOOTPRINT #1) that has a mapped property (mapping happen when one class object references another). Once you map/reference one object to another = MEMORY FOOTPRINT #2. Adding events = MEMORY FOOTPRINT #3, etc and so on.
Custom Sprite
import flash.display.Sprite;
class CustomSprite extends Sprite{
private var _mappedProperty:Object;
public function addMapping(map:Object):void{
_mappedProperty = map;
}
public function finalize():void{
_mappedProperty = null;
}
}
Assuming we're using CustomSprite in many other methods, lets look at some common ways of removing the ojbect.
INCORRECT - in this situation [objToRemove] was not set to null to free its memory:
var objToRemove:CustomSprite = new CustomSprite;
function doSomething(referenceObj:CustomSprite):void{
var methodObj:CustomSprite = referenceObj;
//CRAZY LINES OF CODE
methodObj = null; //frees memory from [doSomething::methodObj]
referenceObj = null; //frees memory from [doSomething::referenceObj]
//objToRemove is not cleared and will remain in memory
}
INCORRECT - in this situation [objToRemove] has a reference object so it will not clean until the reference is removed:
var objToRemove:CustomSprite = new CustomSprite;
var mappedObject:Sprite = new Sprite;
objToRemove.addMapping(mappedObject);
objToRemove.addEventListener(Event.ENTER_FRAME,onEnterFrame);
//CRAZY LINES OF CODE
//remove all children
while(objToRemove.numChildren > 0){
objToRemove.removeChildAt(0);
}
//remove all event listeners
objToRemove.removeEventListener(Event.ENTER_FRAME,onEnterFrame);
//this will NOT work
objToRemove = null;
//reason is objToRemove has a reference object of [mappedObject]
//[mappedObject] is not a child so it needs to be removed manually
//from WHITIN the CustomSprite class using [CustomSprite::finalize()]
Ok... breath... the correct way is actually simple.
CORRECT - here we are using [Dynamic] objects rather than [Static] class objects, this is considered Object Mapping:
//think of this as a global list of objects
var objPool:Dictionary = new Dictionary;
//create a pool reference
objPool['poolObj'] = new CustomSprite;
//CRAZY LINES OF CODE;
//do the normal [null] process
//both of these will work
objPool['poolObj'] = null;
//or
delete objPool['poolObj'];
SUPER ADVANCED CORRECT - no example provided, I have to get back to work lol...
1. Take a ByteArray clone of the class
2. User a Loader to construct the ByteArray as the class, rather than using "new"
3. When finished... unload/remove the loader
4. EVERYTHING will clear... thats how a Loader works!
(Not getting into why and how... too long of an explanation)
Although this works flawlessly... its not generally accepted or suggested in a work environment.
It may sound stupid, but how can I remove a definite child from the stage?
e.g.
function giveMeResult(e:MouseEvent):void
{
if(stage.contains(result))
{removeChild(result);}
addChild(result); // this part works fine, but it adds one over another
}
it adds one result on the top of the previous one.
I want the function "giveMeResult: to remove "result" if is on the stage and add a new one.
UPDATE:*
result is a TextField, and result.txt ="" changes from time to time ...
trace (result.parent); /// gives [object Stage]
trace (result.stage); /// gives[object Stage]
trace (result.parent != null && result.parent == result.stage); // gives true
when
result.parent.removeChild(result);
is written without if statement - gives error TypeError: Error #1009: Cannot access a property or method of a null object reference.
when written inside:
if (result.parent !=null && result.parent == result.stage)
{
result.parent.removeChild(result);
}
nothing happens and new child is added on the top of the previous one.
Thanks to all!!!
The result is simple :)
All I had to do is just change result.txt without even removing it from the stage :)
You need to type stage.removeChild(result); and subsequently stage.addChild(result);
Edit:
Looking at a function similar to yours:
private function func(e:Event) : void {
if(stage.contains(result)) {
stage.removeChild(result);
}
stage.addChild(result);
}
The only way this would add a new instance of the TextField result to the stage, without removing the old one, would be if result has changed. See this flow of execution:
var result : TextField = new TextField();
// An event occurs and func get's called.
// now result will be added to stage.
result = new TextField();
// An event occurs and func get's called again
// This time the stage.contains(..) will return false, since the current result
// is not actually on stage. This will add a second TextField to the stage.
If I am clearly understood what you want, then this code can help you:
if (result.parent != null && result.parent == result.stage)
{
// stage itself contains result
result.parent.removeChild(result);
}
From the docs for DisplayObjectContainer.contains(): "Grandchildren, great-grandchildren, and so on each return true."
So contains means anywhere on the display list, not just direct children. What you want is the parent check Manque pointed out, or simply to remove result from anywhere it might be:
if (result.parent) {result.parent.removeChild(result); }
Though oddly, addChild(result) will automatically remove it from its previous parent - a DisplayObject can only be at one place in the DisplayList at a time, so I'm not sure why you're seeing multiple results...
Is it possible that the "result" you've passed in isn't the result that's already on the stage?
Have you tried?
MovieClip(root).removeChild(result)
[EDIT]
function giveMeResult(e:MouseEvent):void{
if(result.parent != null && result.parent == result.stage){
stage.removeChild(result);
}
stage.addChild(result);
}
All I had to do is just change result.txt without even removing it from the stage
i've a problem to a set a different child index of a Movieclip. This is the code:
function processMusica():void
{
var loadStatus:int=0
var lastHeight:int=0
for (var m=0; m < myXML.BLADE[sup].child("brano").length(); m++)
{
var titolobrano:TextField=new TextField
bladearray[sup].contenitore.addChild(titolobrano)
titolobrano.text=myXML.BLADE[sup].brano[loadStatus].titolo
lastHeight=titolobrano.height
titolobrano.doubleClickEnabled=true
titolobrano.addEventListener(MouseEvent.DOUBLE_CLICK, riproducibrano)
loadStatus+=1
}
if (isPlaying==false)
{
var riproduzioneDetails:MovieClip=new MovieClip
riproduzioneDetails.name="riproduzioneDetails"
var artista:TextField=new TextField
artista.name="artista"
bladearray[sup].contenitore.addChild(riproduzioneDetails)
riproduzioneDetails.x=475
riproduzioneDetails.addChild(artista)
}
setChildIndex(bladearray[sup].contenitore.riproduzioneDetails, bladearray[sup].contenitore.numChildren-1) //<------ PROBLEM HERE!
I want to move "riproduzioneDetails" MC on foreground, but when i attempt to launch application, it give me this error: TypeError: Error #2007: Parameter child must be non-null
I can see two potential problems, but it is hard to say because all the variables are not declared in your code. There may be a problem with your test condition:
if (isPlaying==false)
{
...
}
If "isPlaying" is true, your object "riproduzioneDetails" is never created, so of course it will be null. You have to create your object outside the "if" condition, before testing "isPlaying".
Another potential problem is the way you access your object, with "bladearray[sup].contenitore.riproduzioneDetails". As you used the "addChild" method to store your object, there should logically be a kind of "getChild" method. For instance,
setChildIndex(bladearray[sup].contenitore.getChildByName("riproduzioneDetails"),bladearray[sup].contenitore.numChildren-1)
... may be better.
I'm using a Vector structure in ActionScript 3 to store references to a custom class. My Vector is fixed length for performance reasons, and also because it needs to map 1:1 to another data structure.
I'm trying to figure out how I "remove" an element from this fixed list. I don't want the length of the Vector to change, I just want the value of that element to be "null". Or more specifically, when I test for the truth of that element (eg: if (myVector[index]) { // do something... }), I want that test to fail for that element, since it's "empty".
So naturally, I've tried:
myVector[index] = null;
but that throws a TypeError, as does
myVector[index] = Vector.<MyClass>([]);
So what's the process for "emptying" an element of a Vector?
There must be something wrong with your index variable because
myVector[0] = null;
does not throw a TypeError when I try that. Is index an int or uint?
if you're receiving:
TypeError: Error #1009: Cannot access
a property or method of a null object
reference
than you probably haven't added your class to the object you are trying to manage (IE: you haven't added your Display objects to the stage that you are trying to nullify)
posting more code could help, but something like the following should work for you:
var spriteA:Sprite = new Sprite();
var spriteB:Sprite = new Sprite();
var spriteC:Sprite = new Sprite();
var spritesVector:Vector.<Sprite> = new <Sprite>[spriteA, spriteB, spriteC];
spritesVector.fixed = true;
trace(spritesVector); //[object Sprite],[object Sprite],[object Sprite]
spritesVector[1] = null;
trace(spritesVector); //[object Sprite],null,[object Sprite]
I have a movieclip created with the following code:
var thumbContainer:MovieClip = new MovieClip();
thumbContainer.name = "thumbContainer";
stage.addChild (thumbContainer);
If the window gets larger/smaller I want everything back in place. So I have an stage Event Listener. Now I want to see if this mc exists to put back in place. I've tried different ways but keep getting an error that does not exist.
1120: Access of undefined property thumbContainer.
if (this.getChildByName("thumbContainer") != null) {
trace("exists")
}
and
if ("thumbContainer" in this) {
trace("exists")
}
or
function hasClipInIt (mc: MovieClip):Boolean {
return mc != null && contains(mc);
}
stage.addChild (thumbContainer);
//...
if (this.getChildByName("thumbContainer") != null)
You are adding the thumbContainer to stage and checking for its existence with this. Change stage to this or this to stage.
That said, an even more appropriate way is to keep a reference to the added movie clip and check for existence with the contains method. It determines whether the specified display object is a child of the DisplayObjectContainer instance or the instance itself. The search includes the entire display list including this DisplayObjectContainer instance, grandchildren, great-grandchildren, and so on.
Hence you can easily check using stage.contains(thumbContainer);
if you are having trouble firing errors, you can always resort to a try catch
try{
/// do something that will blow up...
}catch( e:Error ){
trace( "we had an error but its not fatal now..." );
}
the problem was that 'stage' and 'this' are not the same...that's why I couldn't talk to the mc.
this works:
var thumbContainer:MovieClip = new MovieClip();
thumbContainer.name = "thumbContainer";
addChild (thumbContainer);
if (getChildByName("thumbContainer") != null) {
trace("exists")
}