メモリリーク対策のためにremoveEventListenerする方法の一考察

2008 年 11月 19 日

AS3のメモリリークに関しては、数々のFlasherさんのブログで語られていますが、共通して「不要になったオブジェクトをnullするだけじゃなくて、そのオブジェクトの全てのイベントをremoveEventListenerしてね」ということが書かれていると思います。
僕もそこらへんを気をつけて、AS3でコーディングしていたりするのですが、たいてい、

不要になる = 表示リストから消すとき(removeChildするとき)

というのがほとんどなので、不要になるオブジェクトのクラスにREMOVED_FROM_STAGEのハンドラをつけて、その中で全てのイベントをremoveEventListenerしています。もちろんこの「Event.REMOVED_FROM_STAGEのハンドラ」自身もその中でremoveEventListenerしてます。
以下サンプルです。

Actionscript:
  1. package{
  2.     import flash.display.MovieClip;
  3.     import flash.events.Event;
  4.     import flash.events.MouseEvent;
  5.    
  6.     public class TestMC extends MovieClip { 
  7.         /**
  8.         * コンストラクタ
  9.         */
  10.         public function TestMC():void
  11.         {
  12.             //クリックされたらどうのこうのをaddEventListener
  13.             addEventListener(MouseEvent.CLICK, mouseClick);
  14.             //マウスオーバーされたらどうのこうのをaddEventListener
  15.             addEventListener(MouseEvent.MOUSE_OVER, mouseOver);
  16.             //マウスアウトされたらどうのこうのをaddEventListener
  17.             addEventListener(MouseEvent.MOUSE_OUT, mouseOut);
  18.             //リムーブされたらどうのこうのをaddEventListener
  19.             addEventListener(Event.REMOVED_FROM_STAGE, removed);
  20.         }
  21.        
  22.         //各種マウスイベントハンドラ
  23.         private function mouseClick(e:MouseEvent):void{trace("クリックされました");}
  24.         private function mouseOver(e:MouseEvent):void{trace("マウスオーバーされました");}
  25.         private function mouseOut(e:MouseEvent):void {trace("マウスアウトされました");}
  26.        
  27.         /**
  28.         * removeChildされるときに実行
  29.         */
  30.         private function removed(e:Event):void
  31.         {
  32.             //全てのイベントリスナーをリムーブ
  33.             removeEventListener(MouseEvent.CLICK, mouseClick);
  34.             removeEventListener(MouseEvent.MOUSE_OVER, mouseOver);
  35.             removeEventListener(MouseEvent.MOUSE_OUT, mouseOut);
  36.             removeEventListener(Event.REMOVED_FROM_STAGE, removed); //←このハンドラ自身もremoveする!
  37.         }
  38.     }
  39. }

親クラスでこのTestMCのインスタンスを

Actionscript:
  1. mc:TestMC=new TestMC();
  2. addChild(mc);

みたいにして作って表示させて、いらなくなったときは

Actionscript:
  1. removeChild(mc);
  2. mc=null;

としてあげれば、不要となるオブジェクトの「Event.REMOVED_FROM_STAGEのハンドラ」が動いてくれて、その中に書いた「全てのイベントをremoveEventListenerする」処理が動いてくれます。
こんな感じで前もって「removeChildされるときに、イベント参照も全部消えておいておくんなさいまし」と書いておけば、不要になったタイミングで「あー、イベント消さなきゃ。addしたイベントなんだっけ。面倒くせーなー」とかならなくて便利かなと思います。

Tags: ,

Leave a Reply