アクセシビリティ
デベロッパーリソース
加茂 雄亮氏

加茂 雄亮氏

株式会社ロクナナ
ロクナナワークショップ
xingxx.com

作成日:
2009年9月29日
ユーザレベル:
すべて
製品:
Flash Professional
Flash Builder

「ActionScript 3.0 エラーアーカイブス」抜粋

~あなたがどうしても解決できないエラーに直面したときに~

ActionScript 3.0エラーアーカイブスは、初心者が躓きやすく、上級者も戸惑うコンパイルエラー、コンパイラ警告、ランタイムエラーの原因・解決法を掲載した、リファレンスや入門書とは違う、今までに前例がない内容の書籍です。その一部抜粋を、解説を交えてご紹介します。ご購入前に本書のイメージを掴んでいただくために、PDFもご用意しています。是非、目を通してください。

また、本書は日本全国の大手書店やAmazon.comなどのオンラインブックストアで入手することが可能です。
本の構成や詳しい内容・頂いた書評については、著者のブログエントリーで取り上げています。

1118: 静的型 %1 の値が、関連しない可能性が高い型 %2 に暗黙で型変換されています。

このエラーは、コンパイルエラーで頻繁に見かける問題のひとつで、代入しようとしているオブジェクトの型が、定義されている型指定と相反する場合に発生します。

//問題のあるコード
var example:MovieClip = addChild(new MovieClip());

例えば以上のような例です。変数exampleはMovieClipを型指定し、newキーワードを用いてMovieClipを生成、その時、直接Movieclip.addChildメソッドを使って表示リストに追加しています。一見問題の無いように見えるこのコードも、コンパイルするとエラー1118が発生します。型指定されているのがMovieClipクラスに対して、Movieclip.addChildメソッドの戻り値がDisplayObjectクラスだったためです。ここで、MovieClipはDisplayObjectのサブクラスだから問題ないのでは、という疑問をもった方もおられるでしょう。それは誤解です。
例えばもしこの変数に代入されるはずのMovieClipクラスインスタンスが、実はSpriteクラスのインスタンスで、コンパイラがそれを許容する場合、Movieclip.playを実行してタイムラインを再生しようとしても、実際はSpriteクラスなのでタイムラインを持たず、MovieClip.playメソッドはもちろん実装されていないため、矛盾が発生します。このように、スーパークラスインスタンスを、あたかもサブクラスインスタンスとして型変換することをダウンキャストと呼び、バグが発生しやすい手法とされています。この問題を解決するためには、返ってくるDisplayObjectクラスインスタンスが、確かにMovieClipクラスインスタンスであるのか、保証する必要があります。
この時に使われるのが、as演算子です。as演算子は左項のインスタンスと右項のクラスを評価し、そのクラスのインスタンスだったと保証される場合はインスタンスを明示的型変換して返します。もし、保証されない場合、すなわちそのクラスのインスタンスでなかった場合は、nullを返します。

//修正されたコード
var example:MovieClip = addChild(new MovieClip()) as MovieClip;

Warning: 1012: %s 型の変数は undefined にすることができません。値 undefined は %s に型強制された後で比較されます。

ActionScript 2.0で問題の無かった構文にも、問題が発生します。型が厳密に決められたActionScript 3.0では、Boolean,int,uint,Number以外に、型指定された変数、パラメータ、戻り値において、”データがない”ということを表す値はnullになり、型指定されていない変数や、dynamicキーワードによってダイナミッククラスとして設定されているクラス(例えばObjectやMovieClip,Array)に動的に付与された変数に対して、”データがない”場合には、undefinedになります。

//問題のあるコード
var test1:MovieClip;
if (test1 == undefined) { 
}

//問題のないコード
var test2:MovieClip  = new MovieClip;
test2.info = new MovieClip
if (test2.info == undefined) { 
}

上記の例では、変数testにはMovieClipが型指定されていますが、条件文においてundefinedと等価比較されています。前述の通り、MovieClipの”データがない”ことを表す値はnullなので、undefinedになることはなく、コンパイラ警告が発生します。問題のないコードでは、ダイナミッククラスであるMovieClipクラスインスタンスを、test2変数に編集し、そのクラスインスタンスにプロパティinfoがundefinedであるか評価しています。プロパティinfoに代入されている値はMovieClipですが、ダイナミックに追加されたプロパティです。この場合は比較時にエラーが発生しません。型指定されていないプロパティの”データがない”ことを表す値はnullではなく、undefinedだからです。

//修正したコード
var test1:MovieClip;
if (test1 == null) { 
}

RangeError: Error #2006: 指定したインデックスが境界外です。

このランタイムエラーも、非常に出やすく、一目では理解しにくいエラーのひとつです。例えば、表示コンテナの表示リストに対して表示オブジェクトを追加する場合を想定して下さい。下記の例では、表示コンテナとなる変数spriteが、DisplayObjectContainerから継承されたaddChildAt()メソッドを使用して変数childを表示リストに追加しています。

//問題のあるコード
var sprite:Sprite = new Sprite();
var child:Sprite = new Sprite();
sprite.addChildAt(child,1);

//修正したコード
var sprite:Sprite = new Sprite();
var child:Sprite = new Sprite();
sprite.addChildAt(child,0);

addChildAt()メソッドのおもしろい点は、パラメータに表示リストのインデックス位置を指定できる点です。インデックス位置は可変しますが、何も追加されていない状態では0です。ところが、上記のコードでは1を指定しているため、表示リストの総数よりもはみ出しています。そのため、ランタイムからエラーが送出され、実行が停止されます。
このコードの解決法は、実はいたって簡単です。単に表示リストの総数を超えないようにすればよいわけです。単に、常に表示リストの最低値(0)に追加したい場合は、パラメータには0を記します。逆に、常に最前面に表示させたい場合は、addChildメソッドを使用したほうがよいでしょう。それ以外の任意の値に追加したい場合は、DisplayObjectContainer.numChildrenプロパティで総数を取得し、それ未満(つまり、0~numChildren-1)の値を与えるようにします。
なお、このエラーは単に表示リスト関係のメソッド以外にも、有効範囲が設定されたパラメータをもつメソッドで発生します。詳しくは、PDFをみてください。

ActionScript 3.0エラーアーカイブスから抜粋したPDFをダウンロード(PDF / 759KB)

著者について

加茂 雄亮

株式会社ロクナナ
ロクナナワークショップ
xingxx.com

株式会社ロクナナにて、ActionScriptを伴うFlashコンテンツや、AjaxコンテンツなどRIA開発に従事するフロントエンドエンジニア。テクニカルライターとしての一面を持ち、WEB・雑誌・書籍、媒体問わず執筆。また、イベントやセミナーでの講演など、精力的に活動している。