views:

147

answers:

2

In one frame of my fla file (let's call it frame 2), I load a few xml files, then send that data into a class that is initialized in that frame, this class creates a few timers and listeners.

Then when this class is done doing it's work. I call a dispatchEvent and move to frame 3. This frame does some things as well, it's initialized and creates a few event listeners and timers. When it's done, I move to frame 2 again.

This is supposed to repeat as often as I need so I need to clean up the references correctly and I'm wondering if I'm doing it correctly.

For sprites I do this.

world.removeChild(Background); // world is the parent stage
Background = null;

For instances of other classes I do this.

Players[i].cleanUp(world); // do any cleanup within the instanced class
world.removeChild(PlayersSelect[i]);

For event listeners I do this.

if(Background != null)
{
    Background.removeEventListener(MouseEvent.CLICK, deSelectPlayer);
}

For timers I do this.

if(Timeout != null)
{
    Timeout.stop();
    Timeout.removeEventListener(TimerEvent.TIMER, queueHandler);
    Timeout.removeEventListener(TimerEvent.TIMER_COMPLETE, queueCompleted);
    Timeout = null;
}

And for library images I do this

if(_libImage!= null)
{
    s.removeChild(Images._libImage); // s is the stage
    _libImage= null;
}

And for the class itself in the main timeline, I do this

Frame2.removeEventListener("Done", IAmDone);
Frame2.cleanUp(); // the cleanup() does all the stuff above
Frame2= null;

Even if I do all this, when I get to frame 2 for the 2nd time, it runs for 1-2 seconds and then I get a lot of null reference errors because the cleanup function is called prematurely.

Am I doing the cleanup correctly?

What can cause events to fire prematurely?

+2  A: 

For me, the biggest concern is cleaning up listeners, which you are doing. To avoid any errors in listener cleanup, I always check if the item exists, and then if it has the listener; thus:

if(item)
{
   if(item.hasEventListener(MouseEvent.CLICK))
   {
      item.removeEventListener(MouseEvent.CLICK,doSomething);
   }
}

I do a simimlar check before removing child:

if(item)
{
   if(this.contains(item))
   {
      this.removeChild(item);
      item.destroy()//or whatever you code is to clear that element of its own dependencies.
      item = null;
   }
}
jordanx
removing a listener that doesn't exist shouldn't throw an error.
quoo
Thank you. I found the error, wasn't something I suspected but you helped me see how others clear references.
Ólafur Waage
@jordanx. This check `if(this.contains(item))` is wrong. That code could throw an Error. The `contains` method checks if a DisplayObject B is a descendant of DisplayObjectContainer A. But removeChild only works if B is a "direct" child of A (i.e. A is the parent of B). Most of the times, this works, but it's a potential bug. The proper way would be (assuming you already checked item is a non null DPO): `if(item.parent == this)`.
Juan Pablo Califano
A: 

If you want to be able to let the garbage collector to clean up your objects after you set them to null. Then when you add an eventListener use a weak reference, this allows the garbage collector to collect it when its value is null. See the parameters of the addEventListener function:

addEventListener(type:String, 
                 listener:Function,
                 useCapture:Boolean = false, 
                 priority:int = 0, 
                 useWeakReference:Boolean = false)

So for you to not have the null references, you have to set the last parameter to false.

addEventListener(MouseEvent.MOUSE_OVER, function(), false, 0, true);
instead of
addEventListener(MouseEvent.MOUSE_OVER, function());

When you have strong reference eventListeners you have to manually remove them with the removeEventLister function before removing the referenced object.

Edit: jordanx's example isn't valid, due to the fact that even though item is null, the strong reference is still there and null pointers can still take place.

MasterOfObvious