Dynamic Flash

Confessions of a serial code abuser
  • rss
  • Home
  • MTASC
  • Archives
  • About me
  • Goodies
    • Base64 encoder/decoder class
  • My Bookshelf
  • My Talks

Delegate class refined

Thursday, 17 February 2005

Introduced in the Flash MX 2004 7.2 updater, Macromedia’s Delegate class was a neat solution to having event listeners called in a given scope. Joey Lott improved on this with his Proxy class, allowing you to optionally send additional arguments to your event handler.

Unfortunately, when using either of these classes it is difficult to remove an event listener from an object, because the actual event listener is an anonymous function which calls your target event handler method in the specified scope. If you want to remove such an event listener, you basically have two options, dicussed below.

Option 1: Storing a local reference

If you’re only dealing with a handful of event listeners, you could take the option of manually storing a reference to your ‘delegate’ functions, which you can then later use to remove the event listener.

The example below is a little contrived, but the basic scenario is that you want to listen for the first change in a TextArea component in a MovieClip.

import mx.controls.TextArea;
import mx.utils.Delegate;
 
class MMDelegateTest {
  private var _delegate:Function;
  private var _textArea:TextArea;
 
  public function MMDelegateTest (textArea:TextArea) {
    _textArea = textArea;
    _delegate = Delegate.create(this, onTextAreaChange);
    _textArea.addEventListener("change", _delegate);
  }
 
  private function onTextAreaChange(event:Object) : Void {
    trace("MMDelegateTest.onTextAreaChange");
 
    _textArea.removeEventListener("change", _delegate);
    delete _delegate;
  }
}

Here we create the delegate function and store a reference to it in the private _delegate property. We then use the reference when setting up the event listener, and also again in our event handler to remove the event listener after the first call.

This method works both with Macromedia’s Delegate class and Joey’s Proxy class, but can get very hard to manage if you’re dealing with more than a few event listeners. You also have to manually delete the reference to the delegate function when removing the event listener, otherwise the delegate function won’t get garbage collected. Whether this represent a serious concern for you depends on how many delegate functions you’re going to be creating, but memory leakage is never a good thing.

Option 2: Using a temporary object

If storing local references seems like too much of a hassle, you could always store a reference to the delegate function in a temporary object. Then, using Joey’s Proxy class, you could pass this temporary object to the target event handler as one of the extra arguments that you can get up when calling the Proxy.create() method.

import mx.controls.TextArea;
import ascb.util.Proxy;
 
class JLDelegateTest {
  private var _textArea:TextArea;
 
  public function JLDelegateTest(textArea:TextArea) {
    _textArea = textArea;
    var obj:Object = new Object();
    obj.delegate = Proxy.create(this, onTextAreaChange, obj);
    _textArea.addEventListener("change", obj.delegate);
  }
 
  private function onTextAreaChange(event:Object, obj:Object) : Void {
    trace("JLDelegateTest.onTextAreaChange");
    _textArea.removeEventListener("change", obj.delegate);
  }
}

Here you don’t have to worry about storing local references, because a reference to the delegate function is passed to the event handler method as the delegate property of the obj parameter. You also don’t have to worry about deleting the stored reference to the delegate function, since the temporary object will be marked for garbage collection once the event listener is removed.

However, having to create a temporary object every time I was creating an event listener that I might want to remove in the future was unnecessarily cluttering up my code. Also, I would also have to explain the solution (and exactly why it works) to every developer who works on a piece of my code, so I set about finding a better solution.

A better solution?

In the end, the solution that works for me is simple – just have the delegate function pass a reference to itself as the final argument to the real event handler. Presenting the DynamicFlash Delegate class.

import mx.controls.TextArea;
import com.dynamicflash.utils.Delegate;
 
class DFDelegateTest {
  private var _textArea:TextArea;
 
  public function DFDelegateTest(textArea:TextArea) {
    _textArea = textArea;
    _textArea.addEventListener("change", Delegate.create(this, onTextAreaChange));
  }
 
  private function onTextAreaChange(event:Object, delegate:Function) : Void {
    trace("DFDelegateTest.onTextAreaChange");
    _textArea.removeEventListener("change", delegate);
  }
}

So there you have it. No local references, no temporary objects, just plain and simple event listener obliteration. As with Joey’s class, you can specify any number of additional arguments to be sent to the event handler method when it is called, but there is always a final argument sent that contains a reference to the delegate function that can be used to remove the event listener directly.

Event handlers that aren’t interested in the final argument needn’t even declare it as a parameter in their parameter list, but those that are can use that reference to remove the event listener if necessary. As a bonus, you can swap out Macromedia’s Delegate class for this one using simple search & replace as they have the same interface – just replace every instance of ‘mx.utils.Delegate’ in your code with ‘com.dynamicflash.utils.Delegate’ and you’re good to go.

Comments
22 Comments »
Categories
Flash
Tags
ActionScript, events, Flash
Comments rss Comments rss

About Dynamic Flash

Steve Webster is a Senior Web Developer for Yahoo! in London, UK.

He is more than a little concerned that he defines himself in terms of his career, and that he talks about himself in the third person.

Find out more

del.icio.us-ed

  • samuel's squawk at master - GitHub
  • Pixelwave - A native 2D iPhone framework, based on the Flash API
  • Pixelwave - A native 2D iPhone framework, based on the Flash API
  • mnot’s Weblog: Are Resource Packages a Good Idea?
  • Download details: IE App Compat VHD
  • ZSync
  • jQuery source viewer
  • Penetration testing tools - Stack Overflow
  • Logrep
  • DOM Window (jquery.DOMWindow.js)

Recent Posts

  • Moving on
  • iPhone / iPod Touch Development Resources
  • Upgrading your app to AIR 1.5
  • Motivate yourself by doing it in public
  • The trouble with Flash and REST
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox