Recently, I’ve been hacking at low-level AS3 features to try to find a way to load an external image and make a class out of it. Basically, I want to create multiple instances of that image using only the new
operator. The image path isn’t known until runtime, so I’d like to make a special Loader subclass that knows the correct image path to load before it gets instantiated. As you can imagine, that’s not the easiest requirement to meet.
A short time ago, Ben Stucki created a class to load external images as icons for Flex components. It’s a very clever solution. He uses a Dictionary
to associate the image path with the intended parent. I wish I could have used it, but the class I’m trying to create needs to be instantiated somewhere that I can’t access the parent. Like I said, the class itself really needs to know the correct image URL to load. In AS2, it wouldn’t be too difficult to accomplish. You can hack __proto__
in AS2 to do some interesting runtime subclassing to make a unique class for every URL. Unfortunately, Adobe locked things down a bit in AS3 (for performance reasons, mostly), and __proto__
is no longer accessible to developers.
That said, let’s try to remember back even further, to our AS1 days, when true classes didn’t exist. Classes were function objects, and we added member variables and methods through prototype
. Thankfully, class-like functions through prototype
are still possible in AS3. Consider the following code:
var MyImageClass:Function = function():Loader { //we need a Loader that automatically loads our image var loader:Loader = new Loader(); //the URL will come from the prototype loader.load(new URLRequest(this.url)); //our "constructor" returns the Loader! return loader; }; //the image to load in our dynamically created "class" MyImageClass.prototype.url = "yahoo_logo.gif";
This creates a constructor-like function that returns an instance of Loader
. This loader automatically loads an image URL that we place in the function’s prototype
. If you’re using Flex, you could easily modify this function to make it return a SWFLoader
instead.
Usage is surprisingly simple. We pretend MyImageClass
is a real class, and our friend the new
operator takes care of everything.
//add two images to the display list var image1:Loader = new MyImageClass(); this.addChild(image1); var image2:Loader = new MyImageClass(); this.addChild(image2);
Two images will automatically load. That’s perfect!
…well, sadly, it’s not perfect. There’s some bad news. I had hoped this would be able to replace Ben’s code in Flex too, but I quickly discovered that while this special pseudo-class (as I now call it) behaves like a real class, Flash Player knows that it isn’t a real Class
. For example, the icon
style on the Button
component in Flex expects a Class
object. Our pseudo-class is actually a Function
object, and these two types are not compatible. Flash Player will throw a runtime error if I try to set this style to a Function
.
Thankfully, I need these pseudo-classes for a component that I built myself. I can ensure that I type my variables correctly (or at least branch depending on the type) so that both Class
and Function
can be used. As much as I’d like to be able to use these pseudo-classes for icon and skin styles in Flex, that’s just not in the cards.
If you’re interested, I built a utility class called LoaderUtil
with a function createAutoLoader()
that encapsulates this functionality into a simple function where you pass an image URL, and an optional LoaderContext
(for tweaking cross-domain options and other stuff on the Loader), and you receive one of these pseudo-classes back.