わーくあうと!

日々の作業でためになったことをアウトプットすることで自分の成長につながればなと。

Air for iOSでのデータ保存について

ゲームを作ってるとゲーム内の値(所持金、経験値など)をローカルに保存する必要が出てくる。

方法は色々あるが、『SharedObject』や『File』、『SQLite』なんかを使う方法があるらしい。

これは特に迷う事無くSharedObjectを使おうと決めた。理由はオブジェクトをそのまま保存できて自前でシリアライズする手間もなく、一番ラクそうだったから。

カスタムクラスの保存ができない・・・

そんなこんなで使ってみたがカスタムクラスの保存ができない。というかObject型で保存される。少し調べてみたら、『registerClassAlias』関数でカスタムクラスをあらかじめ登録することでカスタムクラスのインスタンスを保存できるようになるようだった。

registerClassAlias("HogeModel", HogeModel);
SharedObject.getLocal(Defines.APP_SO_NAME_SPACE);

↑こんな感じでSharedObject.getLocalの前にカスタムクラスを登録する。

(これはこれで保存するカスタムクラスをいちいち書かないといけなくて面倒だけど)

勝手に保存される・・・

SharedObjectの動きを確認していると、SharedObject.flush()を読んでいなくても保存されていることに気がついた。どこかに.flush()するコード残ってたかなーと探してみたが見当たらない。

あれー、、と思いながらリファレンスのflushの説明を読んでみると

ローカルに永続化された共有オブジェクトを直ちにローカルファイルに書き込みます。このメソッドを使用しない場合、共有オブジェクトがファイルに書き込まれるのは、共有オブジェクトセッションの終了時となります。つまり、SWF ファイルが閉じられるとき、共有オブジェクトが参照されなくなってガベージコレクションされるとき、SharedObject.clear() または SharedObject.close() が呼び出されたとき、のいずれかの時点です。

と書かれている。仕様でした。

これはこれで便利だが、自分が想定していない所で保存されると追い辛いバグを孕みそうな予感がしたので、自前の保存関数をかまして使うことで、自動で保存されないようにした。

コードで書くと下記のような感じ

public class AppData {

    public function AppData() {
    }

    /*
    * SharedObjectを取得.
    */
    public static function getSharedObject():SharedObject {
        registerClassAlias("HogeModel", HogeModel);
        return SharedObject.getLocal(Defines.APP_SO_NAME_SPACE);
    }

    /*
    * (1)SharedObjectの保存領域部分を返す.
    */
    private static var __tmp:Object;
    public static function getDataObject():Object {
        var so:SharedObject = AppData.getSharedObject();

        if(__tmp == null){
            __tmp = ObjectUtil.clone(so.data);
        }
        return __tmp;
    }

    /*
    * (2)保存.
    */
    public static function saveAll():void {
        var so:SharedObject = AppData.getSharedObject();
        //↓__tmpを入れなおしている.
        so.data = AppData.getDataObject();
        so.flush();
    }
}

(1)で保存領域を複製した物(__tmp)を返し、(2)でso.dataに代入しなおして保存している。

これはまぁぶっちゃけ保存し忘れするかもしれないってのとトレードオフの関係なので、やるべきかどうかは個人の自由かなと思う。

以上。そんな感じ。