AS3: List Dynamic Object Properties and Values

A little known feature of AS3 is the ability to not only list an object’s properties but their values as well. They expose this functionality in a really weird way though. Both the for and for each key words yield different results. As a rule of thumb I would suggest always using for because it gives you not only the properties of the dynamic object, but also the values:

var obj:Object = new Object();
obj.foo = "bar";
obj.hello = "goodbye";

for(var key:* in obj)
{
     trace(key + ": " + obj[key]);
}
// Output:
// foo: bar
// hello: goodbye

for each(var value:* in obj)
{
    trace(value + ": " + obj[value]);
}
// Output:
// bar: undefined
// goodbye: undefined

You’ll notice that the first keyword usage, just the for, populates the property name into the iterator “key” , so you can access the property using the Array notation. The second keyword, for each populates the iterator “value” with the value of the properties. Hardly useful when you are serializing a dynamic object and would like to know what property the value belongs to!

So I would suggest always using for unless you really want to use for each for a specific reason.

AS3 / Flex: Dynamic Loading of Bitmaps From a SWC

Say you have a Flex project with a reference to a SWC that you are working with in Flash. This is a common scenario as Flash is the best place to visually organize graphic elements into a single spot for inclusion into a final build of your Flash or AIR project.

You also have a bunch of images in the SWC that you’d like to instantiate without creating wrapper MovieClips for them. A simple strategy would be the following:

  1. Link all your images to their own class names in Flash using the “Linkage” menu option and publish the SWC.
  2. Attach the SWC to your Flex project
  3. Instantiate the classes when you want to using the getDefinitionByName utility function.

Sounds straight forward and simple, right? Unfortunately it’s not the case. Adobe has a couple “Features” baked in that cause a lot of headaches when trying to access these classes dynamically.

SWC Classes (including Bitmap assets) Do Not Get Embedded Automatically Into Your Project

The first problem is that Adobe will not compile any of your library objects that are exported for Actionscript unless you specifically name them inside your Actionscript. This creates unnecessary clutter in your code and wastes resources during runtime because you have to instantiate objects that you very well may never even need to use, simply so Flash can find the class it wants. There are some really weird solutions on the web trying to solve this problem, but the most simplest one is the addition of the “-include-libraries” directive in your compiler options:

-include-libraries “/absolute/path/to/my/assets/assets.swc”

This will force the compiler to include every single linked object, without the need of creating dummy instances (and other such nonsense).

We aren’t out of the woods yet, though.

BitmapData Objects Require 2 Parameters in it’s Constructor … Parameters You Don’t Know The Values For!

Once you have a reference to your bitmap asset’s class, trying to instantiate it will look theoretically impossible. It requires a width and height to be instantiated, but you don’t know these dimensions. The whole point of dynamically loading a class is to take care of all this at runtime, not prior to compiling, so the class is more or less asking you for information that it itself knows but you don’t. Kind of screwy but there’s an easy fix:

var MyCustomBitmapClass:Class = getDefinitionByName("MyCustomBitmapClassNameFromSWC") as Class;
var myUsableBitmap:Bitmap = new Bitmap(new MyCustomBitmapClass(0,0));

Even though we’re passing 0s, the BitmapData class knows to ignore them and instead use its actual image data dimensions. I’m not sure if this is a documented caveat with Adobe, but it works and I’m not complaining.

AS3: The Function and MethodClosure Classes

A quick little note, if you want to pass anonymous functions as parameters as well as regular function pointers, there is a small difference in their Qualified classnames. An anonymous function is not considered a real function but rather a “method closure” and has an internalized classname:

function detectFunctionType (obj:Object)
{
   trace(getQualifiedClassName(obj));
}

detectFunctionType(detectFunctionType);
detectFunctionType(function () {  // This is an anonymous function });

And your output is:

Function
builtin.as$0::MethodClosure

Just something to keep in mind when passing function pointers. In general usage you may want to support both anonymous functions along with declarative ones, so if you are using getQualifiedClassName in your code when working with callbacks, you should accept both of them.

AS3: HTTP Authentication with URLLoader, Sound (loader), Loader

I recently needed to load data from a private feed into both a JSON object (for deserialization) and multiple sound files in MP3 format. The way to do this is rather straight forward, but there were a couple gotchas I encountered along the way. Here they are in no particular order:

  1. - Loader objects (URLLoader, Loader, Sound) will not pass any authentication information in their headers unless the request uses the POST verb.
  2. - A Loader object (or more precisely, a URLRequest object) will not actually use the POST method unless there is some type of data in the URLRequest’s “data” property.

Essentially, if you want to do a simple GET with HTTP Authentication, you can’t. You not only need to do a POST, you also have to send it POST data, even if it doesn’t require it.

Here is an example of setting up HTTP Authentication using the POST method and sending in fake data:

var _queryLoader:URLLoader = new URLLoader();

var _queryRequest:URLRequest = new URLRequest();
_queryRequest.url = "http://yoururlhere.com/";

// POST is required for HTTP Auth headers to be passed
_queryRequest.method = "POST"; 

// Some type of POST data must be present for POST to happen in the first place
_queryRequest.data = "dummy_data=needed_for_post_to_work"; 

var encoder:Base64Encoder = new Base64Encoder();
encoder.encode(Username + ":" + Password)

var authString = "Basic " + encoder.toString();
var _queryAuthorizationHeader:URLRequestHeader = new URLRequestHeader("Authorization", authString);
_queryRequest.requestHeaders.push(_queryAuthorizationHeader);
var _queryTypeHeader = new URLRequestHeader("Content-Type", "application/x-www-form-urlencoded");
_queryRequest.requestHeaders.push(_queryTypeHeader);
_queryLoader.load(_queryRequest);

If you need to pass GET parameters anyways, you could probably pass them in the URL as a query string. I haven’t checked that yet, though.