Sunday, April 8, 2007

How To.Instantiate Class From Class Name

One frequently asked question is how to instantiate a Class if you don't know the Class until runtime. The "new" operator simply operates on a Class. There's no reason that class has to be hard coded. It could be a variable of Class type. The trick then becomes setting the variable. Often this is done by using getDefintionByName() as below:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()">
<mx:Script>
<![CDATA[
import flash.utils.getDefinitionByName;
import myPackage.mySubPackage.MyClass; // all classes you may want to instantiate should be imported.
import myPackage.mySubPackage.MyClass2; // all classes you may want to instantiate should be imported.

public var dummy:MyClass; // forces "MyClass" to be linked in by the complier";
public var dummy:MyClass2; // forces "MyClass2" to be linked in by the complier";

public function init():void {
var className:String;
if (true) { // really this should be a useful conditional
className = "myPackage.mySubPackage.MyClass"; //use fully qualified name
} else {
className = "myPackage.mySubPackage.MyClass2"; //use fully qualified name
}
var definition:Class = getDefinitionByName(className) as Class; // get class
var myInstance:Object = new definition(); // create new instance of the class of type MyClass
}
]]>
</mx:Script>
</mx:Application>


However this requires you to have the fully qualified name. Sometimes this isn't practical. You could thus do something simpler which requires a little more hard coding:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()">
<mx:Script>
<![CDATA[
import flash.utils.getDefinitionByName;
import myPackage.mySubPackage.MyClass;
import myPackage.mySubPackage.MyClass2;

public function init():void {
var definition:Class;
if (true) { // really this should be a useful conditional
definition = myClass;
} else {
definition = myClass2
}
var myInstance:Object = new definition(); // create new instance of the class of type

MyClass }
]]>
</mx:Script>
</mx:Application>


Lastly, any classes that are dynamically instantiated have to have been compiled into the SWF (or retrieved from a module/RSL/etc). Simply importing a Class does not accomplish this. (Importing is simply a way so you don't have to write the package name in front of the class every time.) There are three main ways (that I know of) to link a Class into a project.

The first is the method is to use the Class somewhere in the code. Examples of this include (as above) defining a variable of the class type or assigning the Class to a variable of type Class. Another example is rschmidt's comment below that you can instantiate an array that holds the classes.

The second method is to use the extraClass property of the Frame or Mixin tag. Warning, these methods may cause linkage problems.

Lastly, you can use the compiler options (how boring).

Personally, I think I prefer rschmidt's method. It's the most economical with code (and probably other resources as well).

2 comments:

rschmidt at adobe dot com said...

Instead of using a variable for every type, you can simply declare one variable that is an array and populate it with the types you want to create at runtime. E.g.
var allMyTypes:Array = [MyClass, MyClass2];

Anonymous said...

shouldn't it read :
definition = MyClass; //currently : definition = myClass;

"Flex", "ActionScript" and possibly "MXML" are probably trademarks of Adobe Systems Incorporated.
"Adobe" is a trademark of Adobe Systems Incorporated.
This site is in no way endorsed or sponsored by Adobe Systems Incorporated.
Content Copyright © 2007 Daniel Freiman.
Site Design Copyright by its copyright holder.
The Flex Non-Docs reserves the right to remove comments for any reason.
All ActionScript and MXML code (and ONLY ActionScript and MXML code) on this website is available under the MIT License.