うむるむ

うむるむ は主に flash 周りの話と美少女ゲーム系の話の二本立てで構成されています。



[ AS3 ]
外部swfの動作が異常に重い時 -getDefinitionByName- 後編 - 09/01/16 22:48 by umroom

前回に引き続き getDefinitionByName
fla付きのサンプル作ったのでそれの解説を。
サンプルはアンロードまわりが正常に働いているか、ゴミが残ってないかをちゃんとチェックしてないので、ちゃんと作るときはもっとチェックして下さいませ。
Loader.unload すると子swfのライブラリ情報はどこへ行くのでしょう?それともどこにも行かない?。消えるとしたら getDefinitionByName で作られたインスタンスは影響を受けるのか、受けないのか?
イマイチ整理しきれてないけど、とりあえず解説を以下に。

コンテンツ(子)swf解説
再生しても「コンテンツX」という文字がアニメーションするだけのもの。インタラクション全く無し。
単独でも動くのでこれから始めた方が楽かと思う。contents1~3は構造は同じなのでどれでもOK。

●Main クラス
ドキュメントクラスである Main.as は、単体で動かす時のみ必要なクラスで、親からロードされた時は何も動作しない設計。 startContents でコンテンツのメインクラスである ContentsWrapper を getDefinitionByName で作って addChid。
前回、最後の方で、「~~子swfのメインクラスを ~~addChild する。」って書いたけど、このメインクラスにあたるのが ContentsWrapper 。ドキュメントクラスの名前を Main にしたのは紛らわしかったなと反省。

Main.as のキモは、ContentsWrapper をインポートしていない点。
getDefinitionByName でインスタンスを作る時は対象クラスをインポートしなくてもOKなのだ。その分、インスタンスの型宣言は Object になるけども、親swfも含めるとインポートの必要がない事は多いに意味がある。まぁそれは後で。
先に見たいせっかちさんはクリック

●メインになる ContentsWrapper クラス
これは親swfから getDefinitionByName と addChild されるクラスなので、ステージに配置された時に動作を開始してくれるとありがたいから、Event.ADDED_TO_STAGE を指定してある。子swfのアニメーション開始は Event.ADDED_TO_STAGE が起きた時になる。
サンプルではしてないけど、ContentsWrapper には独自クラス等をインポートしても大丈夫。
子swfに必要な要素は全部このクラスに入れるよう作る。

●最後におまけ程度に fla 解説
開けば分かる、何も無い。中に何もありませんよ。
ガイド化してる ContentsWrapper があるだけ。これは位置合わせするのに置いただけで、置かなくてもいい。
子swfを単独で動作させる時に必要なものがあれば置いてもいい。親から呼ばれるときは ContentsWrapper が作られて持って行かれるだけなので、メインタイムラインは触られもしない。


メイン(親)swf解説
ボタン連打はすんな。対応する様に作ってないから。
親swfもシンプルの極みで、下部のボタンでそれぞれ子swfをロードして表示するだけ。ファイルサイズが軽いからロードバーは一瞬しか出ない。
今回の題材に関係あるのは classes.contents パッケージ内のクラス、ContentsLoader.as と ContentsPanel.as 2つのみ。

処理の流れは、
1、ボタンからロードする子swfのIDを ContentsPanel が取得。表示中のコンテンツがあれば削除する。
2、ContentsLoader が子swfをロード。
3、ロード完了を受けて ContentsPanel が getDefinitionByName で作って表示。
という感じ。

●ContentsPanelの解説。
特筆すべき点は makeContents() のみ。上の流れの3番目のとこ。
中身は子swfのドキュメントクラスの startContents と同じ。
ここでも ContentsWrapper クラスのインポートはしていない、というよりどのクラスを使うのか分からんのに前もってインポートなんて無理。あらかじめ全部インポートしとけばいいじゃん、てなるけどそれはそれで問題があるのでしない。詳細は下で

●ContentsLoaderの解説
まずインポートの段階で、普段あまり見ない ApplicationDomainLoaderContext の2つがある。普通に Loader で読み込んだswfを使う時にはいらないのだけど、読み込んだswfのライブラリ(クラス)にアクセスする時はこれらが必要になる。使い方は下の様に。

loaderContext = new LoaderContext();
loaderContext.applicationDomain = ApplicationDomain.currentDomain;
 
//URLRequest の他に、LoaderContext も引数に加える
loader.load( new URLRequest("hogehoge.swf"), loaderContext );

LoaderContext の指定が無い場合、子swf のクラスにアクセスする(例えば ContentsWrapper)時に、「親swfの中にそんなクラスは無いよ」とエラーが出る。親の中から探して子を見ちゃくれない。ApplicationDomain.currentDomain は、クラスが存在する swf の中から探す指定なので LoaderContext.applicationDomain をそのようにする。

ロード完了後、本来なら addChild(Loader) となるところだが今回それは無し。それどころか早速 unload。
最初に書いたけど、 unload で子swfのライブラリがどうなるのかが不明なので、この辺はかなり怖い。処理のタイミング上、エラーが出ていないだけってことも考えられる。本来の addChild(Loader) の様な時と同様、そのコンテンツが removeChild されるタイミングで消すのが安全かと思う。
今回採用した実案件では、実際にアップして検証した結果問題が起きなかったのでそのままゴーだったけど、ちゃんと頭で理解した方がいい所である。


●getDefinitionByName とインポート
サンプルの場合、ContentsPanel で3つの ContentsWrapper をインポートすると、親swfをパブリッシュする時点で ContentsWrapper が無い or 未完成だとエラーが出て話にならない。また、ContentsWrapper に修正が発生した場合、子swfだけでなく、親の ContentsWrapper も同じにしなきゃならない。そして、インスタンスを作る時に親がインポートしておいた ContentsWrapper を探してしまってさぁ大変。
と問題アリアリである。分担作業もしにくい事この上ない。コンテンツの修正なのに反映させるためだけに本体も再パブリッシュなんて無駄。
と、そういう事です。

インポートすると、その時点でクラスの容量分ファイルサイズが増えるので、それを避けるためにも getDefinitionByName は有効だけど、色々と注意点もあって getDefinitionByName で探すと苦労話がたくさん出てくる。
ReferenceErrorが出る、実体化とかどうなってる?、最初のフレームにチェック、ダミー変数でとりあえず、、などその時それぞれの解決策がいろいろあってまとまっていない(俺の頭が)状態。

どっかに「どんなケースもこれでモジュール管理はバッチリよ!」なテクニックは無いかなー。
俺ルールくらいは作らないとな。

« [ GreenSock ] TweenMax でカスタムイージングしちゃうんです | ブログトップ | [ 雑記 ] ウチのHDDはSeagate、、、 »

トラックバックURL :