3

背景如何在两个SWF文件中使用Action Script 3类时,在一个SWF动态加载另一个SWF文件时解析为相同的类?

我开发的纯动作脚本3(我们使用Flex 4 SDK自动建立我们的,但我们所有的代码必须能够直接在Flash CS4 Professional中编译)一个高度模块化的应用程序。

我们有一个“framework.swc”文件,它包含我们所有模块之间共享的接口定义,我们有一个“mainmodule.swf”加载其他模块,然后我们为其他模块提供各种.swf文件模块。我们使用Loader类,结合ApplicationDomain :: getDefinition()来动态加载类[我们使用“new LoaderContext(false,ApplicationDomain.currentDomain)”]。

问题

我们所有的模块实现了 “AbstractModule” 界面,该界面中的 “framework.swc” 定义。但是,当我实例化一个动态加载的模块时,(模块是AbstractModule)返回false。更重要的是,如果我调用module.someMethod(someobject),其中someobject实现了在“framework.swc”中定义的接口,并且模块的方法需要在“framework.swc”中定义的同一接口的对象,我得到一个运行时错误“TypeError:错误#1034:类型强制失败:无法将_转换为_”。

似乎“mainmodule.swf”和“loadedmodule.swf”(模块I已经加载用于测试),是在内部,使用单独的定义为在“framework.swc”共享接口

问题

我怎样才能让“mainmodule.swf”和“loadedmodule.swf”解决他们的共同界面,共享的定义,使类铸件和分类比较正确地成功吗?

回答

1

好的。这不是最漂亮的解决方案,但它会起作用。基本上,对于每个“AbstractX”接口(将“X”替换为其他内容),您需要创建两个包装类:“ImportX”和“ExportX”。 ExportX的目标是成功地将AbstractX扩展为Object类型,方法是封装AbstractX,提供与AbstractX类型相同的所有方法,但仅使用内置/预定义的数据类型或数据类型,这些类型或数据类型是其签名中的Flash的一部分。ImportX的目标是缩小与AbstractX类型具有相同特征的动态加载对象(但无法转换为输入AbstractX,并且不能识别为AbstractX类型),但其类型为Object的类型为AbstractX接口。 ExportX和ImportX都使用ImportY,ImportZ等;然而,ExportX使用ImportY,ImportZ等来包装参数,将它委托给AbstractX类型的对象,而ImportX使用它们来包装返回值,这是通过委托给Object类型的对象而产生的。为了使这个多一点理解,我提出下面的例子:

 
public interface AbstractX 
{ 
    // The export/import functions are mandatory 
    // for all such interfaces. They allow 
    // for the wrappers to be correctly manipulated. 
    function export() : Object; 
    function original() : Object; 

    // The interface functions vary from 
    // interface to interface. They can 
    // be called something much more appropriate. 
    function interfaceFunction1(param : AbstractY) : AbstractZ; 
    function interfaceFunction2(param : AbstractA) : AbstractB; 
} 
 
// A class of type Import_ always implements Abstract_ 
public class ImportX implements AbstractX 
{ 
    // The constructor for an Import_ Object 
    // is always of type Object. 
    public function ImportX(obj : Object) : void { 
     _loadedobj = obj; 
     _exportobj = obj.export(); 
    } 

    // Every Import_ class must implement a similar "wrap" function: 
    public static function wrap(obj : Object) : AbstractX { 
     var result : AbstractX = null; 
     if (obj != null){ 
      if (obj is AbstractX){ // Don't wrap if convertible, directly. 
       result = obj as AbstractX; 
      }else if (obj.original() is AbstractX){ // Don't double wrap 
       result = obj.original() as AbstractX; 
      }else{ 
       // Needs to be wrapped. 
       result = new ImportX(obj); 
      } 
     } 
     return result; 
    } 

    public function export() : Object { 
     return _exportobj; 
    } 

    public function original() : Object { 
     return _loadedobj; 
    } 

    // For the interface functions, we delegate to _exportobj 
    // and we wrap the return values, but not the parameters. 
    public function interfaceFunction1(param : AbstractY) : AbstractZ { 
     return AbstractZ.wrap(_exportobj.interfaceFunction1(param)); 
    } 

    public function interfaceFunction2(param : AbstractA) : AbstractB { 
     return AbstractB.wrap(_exportobj.interfaceFunction2(param)); 
    } 

    private var _loadedobj : Object; 
    private var _exportobj : Object; 
} 
 
// Although an Export_ object provides SIMILAR methods to type Abstract_, 
// the signatures need to be changed so that only builtin/predefined types 
// appear. Thus Export_ NEVER implements Abstract_. 
public class ExportX 
{ 
    // The constructor to Export_ always takes an object of type Abstract_ 
    public function ExportX(obj : AbstractX) : void { 
     _obj = obj; 
    } 

    public function original() : Object { 
     return _obj; 
    } 

    public function export() : Object { 
     return this; 
    } 

    // For the interface functions, we delegate to _obj 
    // and we wrap the parameters, not the return values. 
    // Also note the change in signature. 
    public function interfaceFunction1(param : Object) : Object { 
     return _obj.interfaceFunction1(AbstractY.wrap(param)); 
    } 

    public function interfaceFunction2(param : Object) : Object { 
     return _obj.interfaceFunction2(AbstractA.wrap(param)); 
    } 

    private var _obj : AbstractX = null; 
} 
 
// The definition of class X can occur in and be loaded by any module. 
public class X implements AbstractX 
{ 
    public function X(/* ... */) : void { 
     //... 
    } 

    public function export() : Object { 
     if (! _export){ 
      _export = new ExportX(this); 
     } 
     return _export; 
    } 

    public function original() : Object { 
     return this; 
    } 

    public function interfaceFunction1(param : AbstractY) : AbstractZ { 
     // ... 
    } 

    public function interfaceFunction2(param : AbstractA) : AbstractB { 
     // ... 
    } 

    private var _export : Object = null; 
} 
 
// Ok. So here is how you use this... 
var classx : Class = dynamicallyLoadClassFromModule("X","module.swf"); 
var untypedx : Object = new classx(); 
var typedx : AbstractX = ImportX.wrap(untypedx); 
// Use typedx ... 
+0

注意:“dynamicallyLoadClassFromModule”不存在。你必须创建它。这仅用于说明目的。 – 2009-07-19 03:11:23

+0

这是测试和工作。不幸的是,每个动态加载的类都需要3个额外的类/接口。如果有更好的,可靠的方法来做到这一点,我会有兴趣听到它。 – 2009-07-19 03:12:23

0

你应该尝试-compiler.external-library-path记录here ......这样,你可以建立一个在接口上有依赖关系的swc,不在其中,但是来自另一个接口,从而避免了碰撞......不知道如何要做到这一点在CS4虽然...

格尔茨

back2dos

+0

看来,这完成后,* .swc文件必须与* .swf文件一起分发。我们只想分发* .swf文件。 – 2009-07-19 03:13:29

0

您可能需要使用运行时共享库​​(RSL)。 RSL允许您执行动态链接。不过,我不知道CS4是否可以打造这些。也许你可以重新考虑“必须能够直接在Flash CS4中编译”的要求,或者考虑通过CS4 IDE中的宏/脚本使用Flex SDK进行编译。

如果这绝对不是一种选择,另一种方法是在模块之间进行更松散的耦合,并且依赖更多隐含的用于模块SWF的通用外部接口而不是代码级集成。

+0

不幸的是,我无法免除使用Flash CS4 Professional构建的要求。所有这些代码最终都将用于带嵌入式艺术作品和其他媒体的* .fla项目。除非有自动化构建* .fla文件的方法,否则在Flash CS4中构建是一项严格的要求。自动化构建是我自己的事情,所以我可以提高生产力。我更像一个UNIX家伙,所以我喜欢用“make”来构建它。 ;) – 2009-07-19 03:16:06

0

我不是100%肯定,如果你需要什么,但Gaia Framework实现全球API,由许多swf共享以相互交互。你可以检查出来,也许有一些想法。现在我面临的情况与您的情况非常相似,所以我正在检查备选方案......此帖非常有用,谢谢!

相关问题