July 24, 2008

event-registration performance

In Flash Player 9, the time required to register a listener for a given event increases as the number of listeners already registered for that event increases. Here are the results of a simple event-registration test on a P4-2.6ghz machine running Windows XP:

  • Registering 1000 listeners for an event took .06ms per registration (i.e., an average of .06ms to run addEventListener() once).
  • Registering 20000 listeners for the same event took .47ms per registration.

The increased per-listener registration time results from Flash Player 9's implementation of a safeguard built into the event-registration system: when a listener asks to register for an event, ActionScript first checks whether that listener is already registered; if so, ActionScript rejects the registration request. Listeners are, thus, prevented from registering multiple times for the same event.

In Flash Player 9, the "already-registered" check uses a linear lookup, comparing the new listener to every existing listener before allowing the registration to proceed. If an event already has 20000 listeners, and a new listener asks to register, ActionScript must make 20000 comparisons before the registration can be allowed (hence the high ".47ms per-registration" cost in the test above).

Adobe has improved the situation in Flash Player 10 by using a hash-table lookup instead of a linear lookup when checking for the existence of listeners at registration time. Registering for an event with many existing registered listeners will, therefore, be much faster in Flash Player 10.

Posted by moock at 08:05 PM

July 17, 2008

TextField.text Gotcha: \n becomes \r

Here's a little TextField quirk: when you assign the string "\n" (newline) to a TextField's text variable, ActionScript automatically converts it to a "\r" character. For example,

var t:TextField = new TextField()
t.text = "Hello\nworld";

trace(t.text.indexOf("\r")); // 5
trace(t.text.indexOf("\n")); // -1

So if you're hunting for a "\n" you've added to a text field, you'll need to search for "\r", not "\n". The docs for TextField's text variable actually point out that "\r" is used:

"Lines are separated by the carriage return character ('\r', ASCII 13)."

But the docs fail to mention that "\n" is converted to "\r".

Posted by moock at 12:52 PM

July 16, 2008

The Charges Against ActionScript 3.0

More than a year has passed since Flash CS3 was released to widely positive reviews, but many Flash users are still frustrated by some of the workflow changes introduced by ActionScript 3.0. The truly problematic changes are relatively few, but together they have a deep effect on the typical Flash user's daily job. In the spirit of working toward solutions, and of giving a formal voice to the collective grumbling of everyday Flashers, I have published an article called The Charges Against ActionScript 3.0 on O'Reilly's InsideRIA.

The article discusses the following issues:

1. The removal of on()/onClipEvent() from Flash CS3 makes creating simple interactivity hard.
2. Getting rid of loaded .swf files is hard.
3. Casting DisplayObject.parent makes controlling parent movie clips hard.
4. The removal of getURL() makes linking hard.
5. The removal of loadMovie() makes loading .swf files and images hard.
6. ActionScript 3.0's additional errors make coding cumbersome.
7. Referring to library symbols dynamically is unintuitive.
8. Adding custom functionality to manually created text fields, to all movie clips, or to all buttons is cumbersome.
9. The removal of duplicateMovieClip() makes cloning a MovieClip instance (really) hard.

You can read the article in its entirety here.

Posted by moock at 12:14 AM

July 15, 2008

Things You Must Do Before Unloading a SWF File

If you load a .swf file into Flash Player 9 with ActionScript 3.0 and subsequently wish to remove it from memory, you must first deactivate it, and then dereference it. If you dereference the .swf without deactivating it, it will continue to consume resources and in some cases might never become eligible for garbage collection.

Here is an unofficial list of tasks required to deactivate a .swf file:

  • Tell any loaded .swf child assets to disable themselves.
  • Stop any sounds from playing.
  • Stop the main timeline, if it is currently playing.
  • Stop any movie clips that are currently playing.
  • Close any connected network objects, such as instances of Loader, URLLoader, Socket, XMLSocket, LocalConnection, NetConnections, and NetStream.
  • Release all references to cameras and microphones.
  • Unregister all event listeners in the .swf (particularly Event.ENTER_FRAME, and mouse and keyboard listeners)
  • Stop any currently running intervals (via clearInterval()).
  • Stop any Timer objects (via the Timer class’s instance method stop()).

Note that the preceding list is, by definition, insufficient because it is neither exhaustive nor officially maintained by Adobe. If you know of a task that needs adding to the preceding list, please sent it to me via email (username colin, domain moock.org).

As of Flash Player 10, the preceding tasks can be performed automatically by calling the Loader class's new method unloadAndStop().

For further discussion, see Charge #2 in my Inside RIA article, The Charges Against ActionScript 3.0 and Grant Skinner's article Additional Information on Loader.unloadAndStop().

Русский

Posted by moock at 09:18 PM

July 02, 2008

convert xml tags to lowercase

Here's a handy little function for converting all tag names and attribute names in an XML object to lower case. Useful for doing case-insensitive matching on tag names and attribute names.

public function xmlTagsToLowerCase (xml:XML):XML {
  // Convert the root tag to lowercase
  xml.setName(xml.name().toString().toLowerCase());
  for each (var attribute:XML in xml.@*) {
    attribute.setName(attribute.name().toString().toLowerCase());
  }
  // Convert all descendant tags to lowercase
  for each (var child:XML in xml..*) {
    // If the node is an element...
    if (child.nodeKind() == "element") {
      // ...change its name to uppercase.
      child.setName(child.name().toString().toLowerCase());
      // If the node has any attributes, change their names to uppercase.
      for each (attribute in child.@*) {
        attribute.setName(attribute.name().toString().toLowerCase());
      }
    }
  }
  return xml;
}
// Usage:
var x:XML = xmlTagsToLowerCase(new XML ("<A C='D'><B>test</B></A>"));
trace(x); // Output: <a c="D"><b>test</b></a>
Posted by moock at 09:49 PM