AS2でリンケージ識別子が衝突する時のまとめ
- 2009 年 10月 30 日
先日、仕事でハマったところのまとめ。
僕の場合、普段は親SWFから子SWFを読み込んだら不用になったタイミングでアンロードします。その方が無駄にメモリー食わないとでしょうし。
しかし、コンテンツ毎に読み込むような、子SWFがいくつもあったりする場合、毎回ローディングするのが鬱陶しい…とか、サーバー負荷が…とかの理由でアンロードしない仕様で作る場合もあったりする。
この時、複数のSWFに同名のリンケージ識別子があると衝突することがあります。
AS2の場合、この回避には識別子をユニークにするしかない(であってる?)と思います。その挙動を記録しておきます。
上記の検証ファイルは、親SWFのindex.swfから、
子SWFのcontent1.swfとcontent2.swfを読み込んで試したもの。
子SWFとなる二つのファイルには、同じリンケージ識別子Mainで、それぞれのクラスを定義した、色違い・マウスアクション違いの矩形をアタッチしています。
content1.swfとcontent2.swf
public var main:MovieClip; public function onLoad():Void{ //Mainをアタッチ this.main = attachMovie( "Main", "main", this.getNextHighestDepth() ); } |
content1.swfのMain。
public var field:TextField; //マウスプレスで「1」を表示 public function onPress():Void{ this.field.text = "1"; this.field._alpha = 100; Tweener.addTween( this.field, { _alpha:0, transition:"easeNone", time:1 } ); } |
content2.swfのMain。
public var field:TextField; //マウスプレスで「2」を表示 public function onPress():Void{ this.field.text = "2"; this.field._alpha = 100; Tweener.addTween( this.field, { _alpha:0, transition:"easeNone", time:1 } ); } |
親SWFの各ボタンは、load、unload、子がアタッチしたMainインスタンスをremoveするボタンを設置。
//content1.swfをロード public function loadContent1():Void{ if( this.content1.main.getBytesLoaded() ) return; //ロード前ならロード if( !this.content1.getBytesLoaded() ){ this.loader.loadClip( "content1.swf", this.content1 ); } //ロード済みの場合onLoad実行 else{ trace("loaded"); this.content1.onLoad(); } } //content2.swfをロード public function loadContent2():Void{ if( this.content2.main.getBytesLoaded() ) return; //ロード前ならロード if( !this.content2.getBytesLoaded() ){ this.loader.loadClip( "content2.swf", this.content2 ); } //ロード済みの場合 else{ trace("loaded"); this.content2.onLoad(); } } //content1.swfアンロード public function unloadContent1(){ this.content1.unloadMovie(); } //content2.swfアンロード public function unloadContent2(){ this.content2.unloadMovie(); } //content1.swfがアタッチしたmainを削除 public function removeContent1(){ this.content1.main.removeMovieClip(); } //content2.swfがアタッチしたmainを削除 public function removeContent2(){ this.content2.main.removeMovieClip(); } |
これを使って、
Content1LoadクリックしてContent2Loadクリックすると、子SWFのMainが表示されます。表示された矩形をクリックすると左側は「1」右側では「2」が表示されます。
続けて、Content1Removeをクリック。左側のmainがremoveされる。
再度、Content1Loadをクリック。再び左側のmainがアタッチされて表示される。
左側のmainをクリックすると、今度は「1」のはずが「2」と表示されます。
removeでは、読み込んだ子のSWF自体をunloadしていません。この時同じリンケージ識別子があると再アタッチの際、あとで設定されたリンケージ識別子のクラスが適用されるみたい。シンボル自体は正しく表示されるのだけれど。
この症状はunloadをした場合とか、上書きで読み込んだ場合等は発生しないです。
Content1Unloadをクリック。Content1Loadをクリックした場合、正しく「1」が表示されます。
再アタッチしなければ問題なさそうな気もする。
とにかくリンケージ識別子のネーミングには気をつけよう。
というか僕的にはunloadしたい。
読み込んだものを消さない仕様の場合(に限らないが…)、複数人で制作する場合って、ある程度、親子それぞれの仕様とかネーミングルールとか気をつけて決めないと結合した時に面倒なことになりそうですね。