In ActionScript-3 in my level editor I have for each level a new object. Old level objects are removed from stage. So only 1 level object is at stage. I don't keep them in an array or something hoping that garbage collection disposes them for me. My problem seems to be that methods of old objects are still referenced by event listeners that would fire events to the new object and also to the old ones. Old objects are not on stage and therefore invisible but when saving I notice that the old levels have a state caused by editing a newer level.
Now: How can I dispose my objects for sure ?
edit: I also have some event listeners added to stage (KeyDown, MouseMove). Might those few be the problem and others that are just added to the object are removed with the object automatically ?
One approach is to simply setup your event listeners to use weak references by setting the userWeakReference
of addEventListener()
property to true:
addEventListener(MouseEvent.CLICK, mouseClickHandler, false, 0, true);
A better pattern is to setup a lifecycle of listeners, such as add listeners on Event.ADDED_TO_STAGE
, then remove them on Event.REMOVED_FROM_STAGE
In your constructor, listen for Event.ADDED_TO_STAGE
:
// listen for added to stage
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
When your class is added to stage, apply your listeners and listen for Event.REMOVED_FROM_STAGE
:
protected function addedToStageHandler(event):void
{
// remove added to sage handler, listen for removed from stage
removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
// setup listeners for class
addEventListener(MouseEvent.CLICK, mouseClickHandler);
addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
}
When your class is removed from stage, remove remaining listeners:
protected function removedFromStageHandler(event):void
{
// remove removed from sage handler
removeEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
// remove listeners for class
removeEventListener(MouseEvent.CLICK, mouseClickHandler);
removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
removeEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
}
Even better yet is to implement a dispose()
function for your class:
public function dispose():void
{
removeEventListener(MouseEvent.CLICK, mouseClickHandler);
removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
removeEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
}
Often I'll implement an IDisposable
interface to my classes, then dispose as:
// remove children
while (numChildren > 0)
{
var displayObject:DisplayObject = removeChildAt(0);
if (displayObject is IDisposable)
IDisposable(displayObject).dispose();
}