カテゴリー別アーカイブ: AS3

カスタムクラスのプロパティをfor..inで出力


wonderflに昔、こんな感じでforkしてみたものがあったんですが、理由が分からなかった部分を調べたまとめ。

通常、for..inをした場合、Objectとして作成したものは出力できますが、カスタムクラスのプロパティだとそれができません。

//Objectだとできる
for(var i:uint = 0; i < LOOP; i++){
    var id:String = 'id' + String(i+1);
    var name:String = 'name' + String(i+1);
    var obj:Object = new Object();
    obj.id = id;
    obj.name = name;
    _listObject.push(obj);
}
for(i = 0; i < LOOP; i++){
    var o:Object = _listObject[i];
    for(var prop:String in o){
        trace(o[prop]);//できる
    }
}

//カスタムクラスのプロパティはでない
for(var j:uint = 0; j < LOOP; j++){
    var id:String = 'id' + String(j+1);
    var name:String = 'name' + String(j+1);
    var obj:TestObject = new TestObject();
    //TestObjectはidとnameをpublic変数に持つものとする
    obj.id = id;
    obj.name = name;
    _listObject.push(obj);
}
for(j = 0; j < LOOP; j++){
    var o:Object = _listObject[j];
    for(var prop:String in o){
        trace(o[prop]);//何も出力されない
    }
}

何故できないのか、と考えてみたんですが、for..inする場合には、そのクラスでpropertyIsEnumerable(プロパティ名)というメソッドを使った時にtrueが帰ってくる必要がありそうです。

ただ、こちらのメソッド、Objectに定義されているものをoverrideすることはできないので、書く必要があるんですが、全てtrueが帰るようにしてもうまく動作しません。prototypeを拡張しても効果無しです。

しかし、たまたまいじっていたらpropertyIsEnumerableがtrueになった、というかfor..inで出力されるようになりました。そのクラスのprototypeにプロパティと同名の変数を定義した場合です。

Object型の場合は値を代入した瞬間に同様の処理をされているのか?とも思いますが、理由は良く分かりません。

サンプルはこちら。

どうせデバッグ用にしか使わないだろうので、処理速度がどう変わるのか、などは検証していません。これが自動化できれば凄く便利な気もします。ただそもそもプロパティの列挙をするためにプロパティを全て知らなければいけないという面倒さがありますし、整形して出力したければ、toStringを実装する時にそのように書いた方が楽な気がしますし。

というわけで、調べたことのメモでした。

カスタムクラスのインスタンスをtraceした時に配列のように内容を出力したい


久々に。仕事がてんてこまいだったのがようやく落ち着いてきました。

表題の件、ずっとできるはず、と思いながらうまく行かなかったのですが、ある時ふと思い立って調べ直してみたらうまく行ったのでメモ。

SpriteやMovieClipを拡張して作るときは、toString()をoverrideして、戻り値を書き出したい値にすればできる様子。

ただ、Objectを拡張しただけのクラス(何もextendsしてないクラス)だとこれだとできない。

Error: Method marked override must override another method.

みたいに怒られます。

どうしたらいいものかと思ってたんですが、直に

public class Hoge {
    public var name:String;
    public var text:String;
    public function toString():String {
        return '['+[name, text]+']';
    }
}

と書けばちゃんとtraceした時にtoStringとして動作するようです。いろいろ調べてみたらtoStringはObjectのObject.prototype.toStringとして書かれているというような記述がありました。

参考:Adobe ActionScript 3.0 * 高度なトピック

真似してみたらこれでもできた。

public class Hoge {
    public var name:String;
    public var text:String;
    prototype.toString = function():String {
        return '['+[this.name, this.text]+']';
    }
}
//----------
var hoge:Hoge = new Hoge();
hoge.name = 'nameTest';
hoge.text = 'textTest';
trace(hoge);  //[nameTest,textTest]

prototypeオブジェクトについてもうちょっと調べてみようと思います。

getChildByNameの謎


通常、タイムラインで配置したオブジェクトや、外部から読み込んだswfに名前をつけようとしても

Error: Error #2078: タイムラインに配置されたオブジェクトの name プロパティは修正できません。

というエラーが出て名前を変更できない。

それならば、と思ってカスタムクラスを作って、

private var _name:String;
public override function get name():String{return _name;}
public override function set name(value:String):void{_name = value;}

ってやって無理矢理名前をセットできるようにしてみましたが、これをやると、

//hogeを名前をつけられるようにしたオブジェクトとする
hoge.name = 'test';//エラーは出ない
OBJ.addChild(hoge);
trace(OBJ.getChildByName('test'));//結果はnull
trace(OBJ.getChildAt(0).name)//結果はtest

という謎の状態になってしまいました。

カスタムクラスのsetterで

super.name = value;

とするとやはりエラーが出るので、setterのnameは上のような動作ではなく、違う動作をすると思われます。何か内部的なIDを割り振っているんでしょうか。あるいは子の名前のリストを内部的に持っているとか?

別の方法で何とかしましたが、思いつきだけで動かしていると痛い目に遭いますね・・・。

余談:

既にunloadしているMovieClipをもう1度unloadしようとすると、エラーになる。

自分でunloadを仕込んだのに忘れてunloadしようとしたら

Error #2099: 読み込み中のオブジェクトは、十分に読み込まれていないので、その情報を表示することができません。

というエラーが。loaderが取得できないのかと思ったら、そもそもその前に削除していたという・・・。まあ確かにloaderが取得できない、という想像は正しいですがw

BitmapとShapeの扱い


ビットマップはタイムラインに置いておくと、パブリッシュ時にShapeに変換される(ただし、AS書き出ししていると、Bitmapになる)。というような話を前に書いてましたが、もうちょっと調べた話。

タイムラインに置いたShapeは隣接レイヤーにShapeがあると統合される。これは上記ビットマップのデータにも有効であり、AS書き出しをしていなければShapeに統合される。

したがって、レイヤー3つに

画像/画像/Shape

という感じでデータをタイムラインに置き、そのクリップ内で

trace(this.numChildren);

すると結果は

1

となる。

このとき、真ん中の画像をASに書き出しすると、

3

となる。

trace(this.getChildAt(0));
trace(this.getChildAt(1));
trace(this.getChildAt(2));

の結果は

[object Shape]
[object Bitmap]
[object Shape]

になる。

勝手にShapeが合成されない方法を編み出したらきっと便利かもしれない。今のところ一番手っ取り早そうなのはシンボルに変換することだろうか。スクリプトで書けばまったく問題にならない部分ではありますが。

ActionScript3.0エラーアーカイブスを少し読んだ。


エラーが出たときにここから探す本・・・というよりは「ふんふんこんなエラーがあるのか」と読むような本の気がする。

だいたいエラーを吐いて困る場合は、「こうすれば解決なのは分かってるけど、実際にその処理は何らかの理由で実装できない」という場合が多い気がするし、そもそもエラーは出ないが動きが変という場合が圧倒的に多い気がする。エラーを吐いてくれさえすればJavaScriptよりは親切な気がする。AS。

なので、これで安心のスクリプトが書ける、というよりはプログラマとして読んで楽しむもののような気がします。

先日

1084:シンタックスエラー:leftparenがcolonの前に必要です

というエラーを吐いたんですが、調べても解決しませんでした。

まあgetterに()をつけ忘れたという初歩的なミスなので数分で解決しましたが。

・・・というかエラー文をちゃんと読めばコロンの前に括弧が足りないと明確に書いてあるんですよね。ちゃんとエラー文を読めよ、と。(left parenで左括弧ですね)

エラー集もいいんですが、FlashDeveloperがハマった罠を集めたAS3罠集みたいなのがあったらすごくいいなぁと思ったりします。

カヤックさん辺りが新サービスとしてやったりするんじゃなかろうかと勝手に思ってるんですがどうなんでしょう。罠共有サイト。問題はどうやって検索させるか、ということでしょうね。どういう状況でどうなったのかという説明を文字だけでするのは至難の業で、絵を使うと検索し辛くなるので、どういう方法で検索させるかが問題になりそうな予感。でもあったらFlash作るのが少しでも楽になるかなぁと思います。