Mike Morearty
10 Jan 2007

Solution to quiz #1: inner functions and garbage collection

Yesterday I posted a quiz with a bit of code that has a bug. Here’s the solution.

The interesting thing about challenging readers to find a bug is that they will inevitably point out things that hadn’t occurred to me. I’ll discuss each of those.

Here’s the code again:

package {
    import flash.display.Sprite;
    import flash.events.Event;

    public class MyClass extends Sprite
    {
        public function MyClass()
        {
            this.addEventListener(Event.ENTER_FRAME,
                function(e:Event):void { trace("enter frame") },
                false, 0, true);
        }
    }
}

Two readers had the answer I was looking for: The callback function is an inner function rather than a member function, but we passed “true” for the “useWeakReference” parameter of addEventListener().

When you pass a regular method to addEventListener(), that method always has a specific “this” object associated with it – the object that was “this” at the point where the reference to the method was created. But when you pass an inner function, inner functions do not have a specific associated “this” object. So unless you created some other sort of reference to the function, e.g. by assigning it to a member variable of an object or something, it will just disappear when garbage collection takes place.

As for other answers: Two readers guessed that the bug was that I was listening for the ENTER_FRAME event, but Sprite doesn’t have a timeline (if you want a timeline, you should extend MovieClip), so it wouldn’t work. I actually don’t know a lot about that part of Flash, but I checked the docs, and it looks like the ENTER_FRAME (aka enterFrame) event is part of class DisplayObject, which is not a MovieClip; the docs say, “Dispatched when the playhead is entering a new frame. If the playhead is not moving, or if there is only one frame, this event is dispatched continuously in conjunction with the frame rate.” The implication there is that you don’t have to have your own timeline in order to listen for frame events. Perhaps you are listening to the playhead of the timeline that contains you? Or maybe no specific timeline is involved – maybe it just means the player has moved to its next frame.

Finally, another reader suggested that since the listener is created inline, it will never be possible to remove it, because there is no way to refer to it. That is certainly true, and I guess it could be considered a bug in some cases, but it isn’t a bug in the sense I was thinking of. For many programs, it is common usage to add event listeners using inner functions, because the program has no expectation of ever needing to remove those listeners.

comments powered by Disqus