例によってProgression Frameworkの話。今日はForLoopコマンドとSerialListを使って、複数のコマンドを連続実行させようかと企んだが、それはProgression Frameworkの仕組み的に無理だったと言う事がわかって終わったって話。
■やろうとしたこと
ForLoopって言う、コマンドを繰り返し実行してくれるコマンドがあったので、早速使おうと。
で、1個だけコマンド実行されてもあんまり意味ないし、SerialList使ってつなげようと、そう言う訳です。
こんな感じ。勿論、実際に使う時はもっと有益なコマンドを使いますが。
- addCommand(
- new ForLoop(10,
- new SerialList(
- new Trace("コマンド1個目"),
- new Trace("コマンド2個目")
- )
- )
- );
すると、どうなるか。
- 理想
-
コマンド1個目 コマンド2個目 コマンド1個目 コマンド2個目 … コマンド1個目 コマンド2個目
で10回繰り返し
- 現実
-
コマンド1個目 コマンド2個目
あれ?1回で終わってる??
- ForLoop
- SerialList
- CommandList(SerialListの親)
- Command(CommandListの親)
execute();
_executeStart();
_executeProgress();
_executeComplete();
- public function execute( extra:Object = null ):void {
- // 無効化されていたら終了する
- if ( !_enabled ) { return; }
- // 実行中なら終了する
- if ( _running ) { return; }
- _extra = extra || {};
- // 処理を開始する
- _running = true;
- ・・・
- まず
execute()
の頭で、_running
の値をチェックし、true
であれば現在コマンドが実行中であると考えて実行を中止する。 - 処理の実行に先立ち、これからコマンドが実行中になると言う意味で
_running
にtrue
を代入。 - protected function _executeComplete():void {
- // 事後処理を実行する
- ・・・
- // 処理を終了する
- _running = false;
- ・・・
execute();
_executeStart();
_executeProgress();
_execute();
リスト内の1つ目のCommandの
execute();
リスト内の2つ目のCommandの
execute();
リスト内のN個目のCommandの
execute();
・・・
_executeFinally();
_executeFinallyComplete();
- protected function _executeFinallyComplete( e:CommandEvent ):void {
- // 事後処理を実行する
- if ( _afterFunc is Function ) {
- _afterFunc.apply( _afterScorp, _afterArgs );
- }
- // イベントを送出する
- dispatchEvent( e );
- }
- // 実行中なら終了する
- if ( _running ) { return; }
■なぜ、ループは1回しか回らないのか?
というわけで、ループする予定が1周で終了してしまった。何故だろうか?どこかに原因がある筈。
この事件の犯人は、一体誰なのか・・・?
実は、原因はCommandとCommandListの、終了時の処理の違いにあった。
まず、以下にCommandの実行時に呼ばれる関数を示す。
こんな感じ。この順序で処理が進んでいく。メインの処理は_executeProgress()
内に記述されてる。
で、次に最初に呼ばれる、execute()
関数のコードを示す。
今回の件で重要なのは、_running
の値。なので、そこに注目する。
見ての通り、次のような処理をしている。
で、コマンドの処理が実行され、いよいよ終了だ!となった時。
通常のCommandであれば、_executeComplete()
関数が呼ばれ、
このように、事後処理(afterで設定した関数を呼ぶ)が行われ、その後_running
をfalse
にしている。これによって、次にまたexecute()
を呼んでも、コマンドを実行することが出来る。
一方SerialListの場合、関数はこんな感じで呼び出される
で、最後の関数_executeFinallyComplete()
の中身はこう。
そう、問題はここである。
大切な大切な、「_running
をfalse
にする」処理がどこにも無い。なので、SerialListは、一旦コマンドが開始されたら永久に「俺今仕事中だから、新しい仕事は後にしてもらえます?」状態に突入してしまうのだ。ということで、ForLoopコマンドが2回目のSerialListを実行しようとすると、
これに引っ掛かって処理が停止してしまう。
しかも悪いことに、この終わり方だとコマンド終了のイベントも送出されないので、ForLoopは以後の処理を一切続けられないと言う危険を孕んでいる(ForLoopは1回1回のコマンドをイベントで管理している)。その上_running
はprivateで、get用のプロパティしかない。なので、この時点で手詰まりなのだ。
つまり、
ForLoopとSerialListは組み合わせるな!
ということだ。
■あとがき
ここまで書いて、
「あ、これフォーラムに投稿した方がよくね?」
と思ったが、長いしもう書いちゃったのでいいや。
最新コメント