注意:这是一个Actionscript项目,而不是Flex项目。

我在RSL中定义了A类(从技术上讲,这是我在Flash IDE中制作的艺术资产,并导出为actionscript。然后将整个.FLA导出为SWC / SWF)。

在我的主要项目中,我有B类,它是从A类继承的。该项目编译良好,没有错误。

但是,当项目运行时,当我尝试创建B类的实例时,出现验证错误。但是,创建A类的实例很好用:

import com.foo.graphics.A;   // defined in art.swf / art.swc
import com.foo.graphics.B;   // defined locally, inherits from A
...
<load art.SWF at runtime>
...
var foo:A = new A(); // works fine
var bar:B = new B(); // ERROR!
// VerifyError: Error #1014: Class com.foo.graphics::A could not be found.


供参考,这是我如何加载RSL:

var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onArtLoaded);
var request:URLRequest = new URLRequest("art.swf");
var context:LoaderContext = new LoaderContext();
context.applicationDomain = ApplicationDomain.currentDomain;
loader.load(request, context);


B类的定义如下:

import com.foo.graphics.A;
class B extends A {}

最佳答案

我不认为这是一个错误。更多的是联系问题。

当您尝试创建B的实例时,不会发生验证程序错误。一旦您的主瑞士法郎载入并由播放器验证,就会发生这种情况。这是一个重要的区别。要了解我的意思,请更改此代码:

var bar:B = new B();




var bar:B;


您仍然会收到错误。

我不知道您是如何构建swf的,但是从错误看来,显然A类(B的父级)已从swf中排除。我可以使用以下mxmlc开关重现此内容:

-compiler.external-library-path "lib.swc"


但是,将其更改为:

-compiler.library-path "lib.swc"


问题就解决了。显然,这种做法无法达到在运行时加载资产的目的,因为这些资产已经被编译到main.swf中(实际上,情况更糟,因为这样做只会增加应用程序的全局下载大小) 。

因此,如果将art lib设置为外部库,则编译器可以进行类型检查,您将在IDE中自动完成等等。尽管如此,您的B类仍取决于定义的A。因此,在运行时,必须在代码中首次引用A时定义B。否则,验证者将发现不一致之处并崩溃。

在Flash IDE中,链接符号时,有一个“在第一帧导出”选项。这是默认情况下导出代码的方式,但是这也意味着可以推迟播放器首次引用类的定义的时间。 Flex将其用于预加载。它只加载swf的一小部分,足以显示预加载器动画,同时加载其余代码(未“在第一帧中导出”)和资产。至少可以说,手动执行此操作似乎有些麻烦。

从理论上讲,如果我正确记得RSL的工作原理,那么使用RSL应该会有所帮助(想法是RSL应该由播放器透明加载)。以我的经验,RSL是一种皇家痛苦,并不值得麻烦(仅举几个令人讨厌的“功能”:您必须对URL进行硬编码,在必要时很难使缓存无效,等等。也许是一些RSL问题已经消失,现在事情可以正常使用了,但是我可以告诉你,自从Flash 6以来,我一直在使用Flash,并且多年来,我会不时地使用RSL的想法(因为这个想法本身就产生了很多从某种意义上讲,不考虑实现),只是在发现一个问题之后才放弃它。

避免此问题(根本不使用RSL)的一种选择是让shell.swf加载art.swf,并在加载后加载当前代码。由于到您的code.swf加载时,art.swf已被加载,因此验证程序在检查com.foo.graphics.A(在code.swf中)时将找到com.foo.graphics.B(在art.swf中)。

    public function Shell()
    {
        loadSwf("art.swf",onArtLoaded);
    }

    private function loadSwf(swf:String,handler:Function):void {
        var loader:Loader = new Loader();
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, handler);
        var request:URLRequest = new URLRequest(swf);
        var context:LoaderContext = new LoaderContext();
        context.applicationDomain = ApplicationDomain.currentDomain;
        loader.load(request, context);
    }

    private function onArtLoaded(e:Event):void {
        loadSwf("code.swf",onCodeLoaded);
    }

    private function onCodeLoaded(e:Event):void {
        var li:LoaderInfo = e.target as LoaderInfo;
        addChild(li.content);

    }


在当前的主类中,添加以下代码:

        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);


将构造函数逻辑(如果有的话)移到init方法,它应该可以正常工作。

但是我不喜欢这种方法的原因是您必须为shell创建另一个项目。

通常,我要做的是有一门课,以替代图形资产。

    private var _symbol:MovieClip;

    public function B() {
        var symbolDef:Class = ApplicationDomain.currentDomain.getDefinition("com.foo.graphics.A") as Class;
        _symbol= new symbolDef();
        addChild(_symbol);
    }


由于com.foo.graphics.A只是图形资产,因此您实际上不需要代理其他内容。我的意思是,如果您想更改xywidth等,则只需在代理中更改这些值,结果实际上是相同的。如果在某些情况下不正确,则可以添加实际作用于代理对象(com.foo.graphics.A)的getter / setter。

您可以将其抽象为一个基类:

public class MovieClipProxy extends MovieClip {

    private var _symbol:MovieClip;

    public function MovieClipProxy(linkagetName:String) {
        var symbolDef:Class = ApplicationDomain.currentDomain.getDefinition(linkagetName) as Class;
        _symbol = new symbolDef();
        addChild(_symbol);
    }

    //  You don't actually need these two setters, but just to give you the idea...
    public function set x(v:Number):void {
        _symbol.x = v;
    }

    public function get x():Number {
        return _symbol.x;
    }
}

public class B extends MovieClipProxy {

    public function B() {
        super("com.foo.graphics.A");
    }


}


同样,将应用程序域作为依赖项注入(并将实例化机制移至其他实用程序类)可能对某些项目很有用,但是上面的代码在大多数情况下都很好。

现在,这种方法的唯一问题是B的构造函数中的链接名称不会由编译器检查,但是由于它仅位于一个位置,因此我认为它是可管理的。并且,当然,在尝试实例化依赖于它的类之前,应确保已加载资产库,否则它将导致期望。除此之外,这对我来说还算不错。

聚苯乙烯

我刚刚意识到,在您当前的情况下,这实际上可能是一个更简单的解决方案:

public class B extends MovieClip {

    private var _symbol:MovieClip;

    public function B() {
        _symbol = new A();
        addChild(_symbol);
    }

}


要不就:

public class B extends MovieClip {

    public function B() {
        addChild(new A());
    }

}


相同的代理思想,但是您不必担心使用应用程序域从字符串实例化对象。

关于apache-flex - 不能从RSL中定义的类继承吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3107178/

10-09 02:11