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共享以相互交互。你可以檢查出來,也許有一些想法。現在我面臨的情況與您的情況非常相似,所以我正在檢查備選方案......此帖非常有用,謝謝!

相關問題