开发者

Is it possible to dynamically create an instance of user-defined Class in Action Script 3?

I got a factory, where Action Script follows an xml and builds DisplayObject hierarchy out of it. It is meant that script doesn't know beforehand what elements it will encounter in xml and therefore doesn't know what user-defined factory classes it will need.

I know that it is possible to do something like this:

var rect:*, className:String = "flash.geom.Rectangle";

if (ApplicationDomain.currentDomain.hasDefinition(className)) {         
    rect = new(getDefinitionByName(className));
}

And Rectangle instance will get instantiated. But as soon as I replace flash.geom.Rectangle with something user-defined, like my.factory.Block it stops working and if I comment out conditional I get simple: "Variable Block is not defined" error.

Obvious workaround would be to create an instance of my.facto开发者_高级运维ry.Block (and all other components), prior to activating the factory, but that kinda ruins whole point of dynamic component factory.

Of course I have: import my.factory.*; statement at the top of the script.

Is there any smarter solution to this?


As others have pointed out, the problem is most probably that of classes not being included in the compiled swf. As Daniel pointed out, an import is not enough, you need a reference to the class. You don't, however, need to declare a variable, as Cay stated, you can just do as follows:

MyClass;

Although, if you're using the mxmlc to compile, you can use the -includes option to specify a class, or classes, that you would like to force to be included in the compiled swf. The nice thing about this is it doesn't require you to have a reference in your code. It looks like this:

-includes com.example.MyClass com.example.MyOtherClass

If you have a really big package of classes you want to include, but don't want to write out the class name for every class, you can compile the package as a swc, using the compc, and the use the -include-libraries option of mxmlc to include the entire package.


i've never used ApplicationDomain.currentDomain.hasDefinition(className), instead I've been using the try catch way of doing this, but looks like this is the better way of doing this. so thanks for that.

anyway,

I've come across (i think) this same issue before. The problem is that the compiler doesn't compile all your my.factory.*; assets. What I have done is created a dummy instance of each object I will require.

privete function uncalledFunction():void{
  var s_01:Block;
  var s_02:Triangle;
  var s_03:Pineapple;
}

This "tricking it" has worked for me, but I'm interested to see if there are any more elegant solutions.


Others have offered solutions, but here is an explanation of what is happening.

The import statement does not actually include the class code when you compile. It basically brings the type signature(s) into scope so that the compiler doesn't barf.

From http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/statements.html#import

If you import a class but do not use it in your script, the class is not exported as part of the SWF file. This means you can import large packages without being concerned about the size of the SWF file; the bytecode associated with a class is included in a SWF file only if that class is actually used. One disadvantage of importing classes that you do not need is that you increase the likelihood of name collisions.

The solutions presented provide methods for getting the classes into the SWF.

Edit:

OK, I think I better understand your original question. The class code has to come from somewhere. It either has to be linked in via one of the methods presented, or you need to put the classes into children SWF(s), and update your logic to get the class name, load the proper child SWF, then get the class definition from the ApplicationDomain of the SWF you just loaded.


I've done something similar to Daniel's response, but you don't even need to declare variables... it's enough with this:

Block; Triangle; Pineapple;


Here's some code that I just threw together. I tried it on the Timeline and it works. Is it what you want?

import flash.system.ApplicationDomain;

trace( makeInstance( "flash.display.Sprite" ) ); //[object Sprite]
trace( makeInstance( "flash.geom.Rectangle" ) ); //(x=0, y=0, w=0, h=0)
trace( makeInstance( "hi.there" ) ); //null

function makeInstance( className : String ) : *
{
    var MyClass:Class;
    var instance : * = null;

    if ( ! ApplicationDomain.currentDomain.hasDefinition( className ) ) return null;

    MyClass = getDefinitionByName( className ) as Class;
    return new MyClass();
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜