株式会社antsのホームページへようこそ。

[AS3.0]カスタムクラスのシリアライズ

0
Posted in Lab. By tanaka

FlashにはAMFというバイナリ通信のフォーマットがあって、LocalConnectionやSharedObjectでもこの形式でデータを扱ってます。AIRでオブジェクトをローカル保存するときなんかもそうです。で、AMFがデフォルトで対応してるデータ型は勝手にクラスのマッピングをしてくれますが、そうじゃないオブジェクトを使いたいときもあります。要は自作クラスのインスタンスも保存&復元したいってわけです。
これをやるには全部のプロパティが取り出せて、後で自動でnew()して設定し直せないとダメですよね。なのでプロパティが全部publicなクラスは行けるようです(黙示的なgetter/setterもオッケー)。あと、コンストラクタに必須パラメータがあるとnew()するとき困るのでダメです。じゃあprivateなプロパティは無理?というのを調べたところ方法があるっぽいので書き留めておこうと思います。


えーと、その前にAMFでデフォルト以外のデータ型を使うときにはregisterClassAlias()でクラスのエイリアスを登録しとく必要があります。エイリアスってのはクラスの実体に対するショートカットみたいなもので、オブジェクトをシリアライズするときにエイリアスが一緒に保存されて、後でデシリアライズするときにエイリアスから元のクラスを見つけてインスタンス化するんだと思います。
さて、実際にprivateメンバを持ったクラスを試しにローカルSharedObjectに保存してみます。↓こんなクラスです。


package {
    public class CustomClass {
        
        public var foo:String;
        private var bar:String;
        
        public function CustomClass(a:String = null, b:String = null) {
            foo = a;
            bar = b;
        }
        
        public function dump():void {
            trace("foo = " + foo);
            trace("bar = " + bar);
        }
        
    }
    
}

テキトーに保存して…


registerClassAlias("CustomClass", CustomClass);
var so:SharedObject = SharedObject.getLocal("serializeTest");
so.data.customObj = new CustomClass("Hello", "Work");

取り出すと… publicな方しか保存されてない。


registerClassAlias("CustomClass", CustomClass);
var so:SharedObject = SharedObject.getLocal("serializeTest");
so.data.customObj.dump();
so.clear(); //ついでに消去

//出力
foo = Hello
bar = null

ということで、上記のクラスを改造してIExternalizableインターフェースのreadExternal()とwriteExternal()メソッドを実装します。


package {
    
    import flash.utils.IExternalizable;
    import flash.utils.IDataInput;
    import flash.utils.IDataOutput;
    public class CustomClass implements IExternalizable {
        
        public var foo:String;
        private var bar:String;
        
        public function CustomClass(a:String = null, b:String = null) {
            foo = a;
            bar = b;
        }
        
        public function readExternal(input:IDataInput):void {
            foo = input.readUTF();
            bar = input.readUTF();
        }
        
        public function writeExternal(output:IDataOutput):void {
            output.writeUTF(foo);
            output.writeUTF(bar);
        }
        
        public function dump():void {
            trace("foo = " + foo);
            trace("bar = " + bar);
        }
        
    }
}

すると、おんなじ処理でも今度はprivateメンバが復元されました。


//出力
foo = Hello
bar = Work

今回はString型を保存するのでI/OにreadUTF()とwriteUTF()を使ってますが、違う型の場合はそれに合わせたメソッドを使います。まあ、本来の用途からずれているのかも知れませんが、こんな感じです。