This will be old news for a lot of you, but pretty interesting to many more.
If you have been using v2 components, there’s a good chance you are using createObject or createClassObject. I think a lot of people assume that these were commands added to the base ActionScript 2.0 language. Not so. They are simply functions written in external ActionScript class files. They are functions added to MovieClip’s prototype. So you can always call one of those functions from any timeline or MovieClip based component, and they will be available.
I knew this was the case, but I wasn’t totally sure how they came to be available PRIOR to any v2 component being put on stage. After all, a component’s constructor only runs when the component is put on stage, and that’s generally what causes any code in its class to execute. But, as soon as you place a v2 component in your library, these commands will be available, even if the component never gets instantiated.
So here’s the deal. Within any v2 component is an instance of UIComponent. Within that is an instance of UIObject. Within that is an instance of UIObjectExtensions. These are all just movie clips exported with those linkage names and class names. Now, if you look in the mx/core/extensions/UIObjectExtensions.as file in your configuration directory, you’ll see a static function Extensions. This is where createClassObject, and several other extensions get added on to MovieClip. There are also some exensions to TextField, and additional extensions added within UIComponentExtensions.as.
But how does this function get run even before an instance of the component is constructed? Well, if you look a little further down in the same .as file, you’ll see this little line:
static var UIObjectExtended = Extensions();
Here, we create a static variable, UIObjectExtended. This is never used, but is initialized to the return value of the Extensions function. If the component is to be exported with the movie, either by setting it to be exported on first frame, or including it on the timeline anywhere in the movie, then Flash will export its classes on frame 1 (or whichever frame you specify it to export classes). At that point, the classes are initialized, and any static functions or variables are made available. When the UIObjectExtended variable is initialized, it forces Flash to execute the Extensions function, which adds all those extensions. Voila! A bit convoluted, but it works.
To add to that, for people wanting to make their components friendly with these methods they should define these properties in their class (below is an example I took from the Slider):
static var symbolName:String = “Slider”;
static var symbolOwner:Object = mx.controls.Slider;
Take note these are static properties, the symbolName property is how createClassObject knows what symbol to attach.
This makes me wonder which method is cleaner, having a class that must be instantiated to extend other classes’ prototype objects (yuck), or puting such declarations on a #initclip block.
Jonas,
the code described here runs actually in an #initclip block (that’s where classes are defined), and doesn’t require a class to be instantiated, that’s the whole point!
The problem is, the Flash compiler doesn’t allow you to run code in a class definition. However, you can assign a value to a static class variable, and that value can be calling a static class method. That allows you to run code as the class is defined, without actually creating an instance.
That’s indeed a backdoor implementation, but at least it does allow you to run that code when it’s needed to run.