でらうま倶楽部

バカってゆうか、ゲームを作る事しか能の無いプログラマの、面白おかしな日々を綴ってみる実験。

JSON

C++でJSONを読み書きするならpicojson

さいきんC++始めました。

まだ始めて2、3日なのですがCにクラスとか色々マクロで拡張を施した言語という印象です。

元々の出発点が「C with Classes」というCの拡張なのだからだと思います。

で、まず標準出入力やファイル出入力のやりかたとか触った後に試したのがJSONのパーサー。
json
ググって見たらpicojsonなるものを発見!これなんとヘッダファイルだけで実装されています。そういうの好き。

こんな感じで使います。

picojson::value json;
cin >> json;

picojson::object& o = json.get<picojson::object>();
int hoge = o["hoge"].get<double>();
bool fuga = o["fuga"].get<bool>();
string piyo = o["piyo"].get<string>();
picojson::array hogehoge = o["hogehoge"].get<picojson::array>();
楽過ぎ!

o["fuga"] = (picojson::value)string("hogehoge");
o.insert(map<string, double>::value_type("piyopiyo", 10.0));
cout << json;
値の変更と出力は以上!
プログラマにこんな楽させちゃダメですよ。 嘘。

ただ、VC2003だとビルド時にエラーが出るので、こうしました。
#ifdef _MSC_VER
#undef getc /* FIXME:VC2003 */
#define SNPRINTF _snprintf /* FIXME:VC2003 */
#pragma warning(push)
#pragma warning(disable : 4244) // conversion from int to char
#else
#define SNPRINTF snprintf
#endif
ヘッダの上の方の部分ですが、VC2003だとなんか色々問題があった模様。

あと356行目は
    bool expect(int expect) {
skip_ws();
if (getc() != expect) {
ungetc();
return false;
}
return true;
}
返却する型はintじゃなくてboolかな…。

そして609行目
  inline bool operator==(const value& x, const value& y) {
if (x.is<null>())
return y.is<null>();
#define PICOJSON_CMP(type) \
複数ファイルで使おうとするとリンクエラーになるのは、ここにinlineが抜けてたからかな…。

まだC++の理解度が0.5%程度なので間違いも多々ありますが…ビルド時に警告は出ないのでこれでいいのではないかと。

こうやって外部の設定ファイルが読めるようになったらもうコッチのもんですよw
1/60のループはglutでサクッとできてるし、あとはアプリの実装を書くだけになりました。


こんな素敵なJSONパーサーを書いてくれたkazuhoさん、どうもありがとうございます!多謝。

ではまた次回。

iPhone TouchJSON1.0.8登場。ついでにスタティックライブラリを極める。

気づけばTouchJSON1.0.8が4月末にリリースされとりました。

JSONは軽量かつ汎用なテキストフォーマットで、TouchJSONはそのiPhone向けのシリアライザ/デシリアライザなり。

最近の部長のお気に入りで、このブログでも過去何度か登場しとります。詳しくはそっちを見てちょ。

とりあえず本家からダウンロードしてきて、適当な場所にファイルを解凍したとこから解説スタート。
  1. Xcodeのメニューから「ファイル->新規プロジェクト」
  2. 左のメニューでiPhoneOS内「Library」を選び、右の一覧から「Cocoa Touch Static Library」を選んでから「選択…」ボタンを押す
  3. TouchJSON_1.0.8フォルダの一つ上のフォルダを選び、名前を「TouchJSON_1.0.8」にして「保存」ボタンを押す
  4. 「置き換えてもいいですか?」と警告されるが、構わず「置き替え」ボタンを押す
  5. いきなりClassesグループを削除して、代わりにTouchJSON_1.0.8/Source以下をプロジェクトに加える
  6. Xcodeのメニューから「プロジェクト->アクティブターゲット"TouchJSON-1.0.8を編集"」を選ぶ
  7. 出てきた設定のうち、プロダクト名を「TouchJSON」に変更したら準備完了!
  8. さっそくビルドしてみる。完了すると TouchJSON_1.0.8/build 以下に Debug-iphoneos/libTouchJSON.a とか Debug-iphoneossimulator/libTouchJSON.a とか出来とるので、自分のプロジェクトにリンクして使う。
photo1まぁだいたいこんな感じです。で、実は7の部分がなにげに重要で、Xcode上でプロダクト名(最終的に出力されるファイルの名前)を変えたい時の技です。これ、非常にわかりにくいと思うんで(他の方法で操作できない)、覚えておいて損は無いでしょう。

なぜなら、「プロジェクト->名称変更」だと、今回みたく名前の後ろにバージョン番号がついとると、その数字だけは変更できないんだよね。Xcode空気読みすぎ!

そしてiPhoneのスタティックライブラリを作る場合、実機用のDebugビルドとReleaseビルド。そしてシミュレータ用のDebugビルドとReleaseビルド。最低4回のビルドが必要です。バージョンはなるべく若いと、より多くのiPhoneをサポートできるので、問題なければデバイスは2.2.1、シミュレータは3.0でビルドしておくとよいかも(まだよくわかってない)

そんで!

作ったスタティックライブラリを自分のプロジェクトで使う場合、Xcodeのメニューから「プロジェクト->プロジェクト設定を編集」を選び、「他のリンカフラグ」「ヘッダ検索パス」「ライブラリ検索パス」を自分の環境に併せて編集する。

photo2部長の場合、ライブラリのヘッダは ~/src/Lib/Headers に、ライブラリ本体(.a)は ~/src/Lib/Library/~ に置いてあるので、「他のリンカフラグ」には「-lTouchJSON」を追加。「ヘッダ検索パス」には「~/src/Lib/Headers」を追加。「ライブラリ検索パス」には、「~/src/Lib/Library/$(BUILD_STYLE)-$(PLATFORM_NAME)」と追加してあります。

「ライブラリ検索パス」にややこしい設定を追加しとりますが、こうしとくとビルド時に
  1. 実機向けDebugビルド
    ~/src/Lib/Library/Debug-iphoneos/TouchJSON.a
  2. 実機向けReleaseビルド
    ~/src/Lib/Library/Release-iphoneos/TouchJSON.a
  3. シミュレータ向けDebugビルド
    ~/src/Lib/Library/Debug-iphoneossimulator/TouchJSON.a
  4. シミュレータ向けReleaseビルド
    ~/src/Lib/Library/Release-iphoneossimulator/TouchJSON.a
と自動的に解釈され、上で説明した4タイプのライブラリを適時リンクしてくれるようになって実に都合がよろしいのだ。


世の中便利で多機能なライブラリが沢山公開されとるんで、こうして積極的に取り込んでいきましょう。そんで、自分で作ったライブラリが他のプロジェクトで使われるようになったら最高だね。

iPhone ちょっと賢いデバッグ・リリース時のファイル管理手法+オマケ

楠田さんと高濱さんによるお気楽ネットTV「遊戯の薬」の第三回目が公開されとりまーす。

んで、ケータイの人向けのYoutubeリンク…。
前半
後半

photo1写真はそのゲスト長谷川杏里さんからだ!
あ、ありがとうございまする…(涙)

いくつになっても嬉しいわ。
それは誕生日。

前置きはこのへんにしといて。

iPhoneアプリでは、実機上でパラメータ調整をしてそれを保存する場合、アプリごとに用意されている Document フォルダに書き出すのが慣例っぽいです。

でもこれ、リリース時には余計な機能。なのでそのへんまとめて面倒みてくれる小さな関数群を作りました。

ゲームのセーブデータや設定なんかは、初期データをリソースに含めておけば初期化についてはプログラムを書く必要が無くなります。セーブデータを削除すればおしまい。みたいな。

ついでにTouchJSONによるJSONファイルの読み込み処理も若干最適化。


// 与えられたファイル名をリソース内での完全なファイル名に変換
NSString *GetResourcePath(NSString *file, NSString *type)
{
    return [[NSBundle mainBundle] pathForResource:file ofType:type];
}

// 与えられたファイル名をDocumentフォルダ内での完全なファイル名に変換
NSString *GetDocumentPath(NSString *file)
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    return [[paths objectAtIndex:0] stringByAppendingPathComponent:file];
}

// ファイルが存在するか調べる(GetResourcePath() か GetDocumentPath() で取得したパスを渡す)
BOOL IsPathExists(NSString *path)
{
    return [[NSFileManager defaultManager] fileExistsAtPath:path];
}

// デバッグ時とリリース時で勝手にファイルを読みかえる
// DEBUG   常にDocumentフォルダ優先
// RELEASE saved=NO Document フォルダ無視
NSString *GetFilePath(NSString *file, BOOL saved)
{
#ifdef DEBUG
    saved = YES;
#endif
    NSString *path = nil;
    if(saved)
    {
        path = GetDocumentPath(file);
        if(!IsPathExists(path)) path = nil;
    }
    if(!path) path = GetResourcePath(file, nil);

    return path;
}

// JSON 読み込み
id ReadJSON(NSString *file, BOOL saved)
{
    NSData *json = [NSData dataWithContentsOfFile:GetFilePath(file, saved)];
    return [[CJSONDeserializer deserializer] deserialize:json error:nil];
}

// JSON書き出し(Document フォルダへ書き出す)
void WriteJSON(NSString *file, id dict)
{
    NSString *jsonString = [[CJSONSerializer serializer] serializeObject:dict];
    [jsonString writeToFile:GetDocumentPath(file) atomically:YES encoding:NSUTF8StringEncoding error:nil];
}


フツーは
NSString *path = GetFilePath(@"hoge.txt", NO);
としておけばオッケー。

セーブデータなど、常に Document フォルダを優先させたい場合は
NSString *path = GetFilePath(@"hoge.txt", YES);
とします。

この手法、PS2の時にもよく使ってたワザで、その時はディスクから読み込むかサーバーから読み込むかを指定できるようにしてました。
アプリ側からは区別なく「ファイル名指定で読み込む」だけになってて、コンパイルオプションでディスク優先にできたりサーバー優先にできたり。バックグラウンド読み込みにも対応しててかなり完成度は高かったです。でもその理由を忘れた(笑)


JSON 読み込みは、ちょっと前の記事からより簡潔&汎用的に。


そうそう。デバッグビルド時のコンパイルオプションに「-DDEBUG」を追加しておくのを忘れずに。

時代遅れのデータ管理法とはさっさと縁を切れ。

このブログを読んでくれてる人は、各種データをソースコード内にstaticな構造体で用意するなんてありえない!くらいに思ってる人ばかりだと思いますがメモ。

ゲーム内で扱うデータを極力テキストファイルベースで扱うのには主に3つの理由があると思ってます。
  1. 人間が読める
    パッと見で内容を把握できるから、データの見通しが非常に良いです。バイナリデータとにらめっこにながら「12バイト目が体力値で…」とか無理。
  2. テキストエディタさえあれば編集できる
    Photoshopなどの高価なソフトがなくても、誰でもどこでも編集可能。やろうと思えば iPhone上でだって編集できます。
  3. CVSやgitなどのバージョン管理システムで管理で管理できる
    た とえ複数の人間で同時にデータを触った時でも、データが壊れてしまう事無く全ての変更が正しく反映されます。
今の世の中、JSONを はじめXMLやYAMLなど、様々なテキストベースの規格とそのパーサーが公開されています。以前は自分で実装するしかなかったこれらの便利な仕組み。積極的に使った方がお得だし、開発時間をかなり節約できると思うよ。


photo1さて、このブログでちょくちょく取り上げとるTouchJSON

Objective-Cで書かれた軽量JSONパーサー。もちろんiPhoneでも動きますし、部長もバリバリ使ってます。

なのですが…使ってて困った事が1点。

それは、扱う型が、NSDictionaryやNSArrayだということ。これだと、読み込んだデータを書き換えられません。たとえば、セーブデータとかね。

で、どーするかっていうと、そんなNSDictionaryやNSArrayを一気にNSMutableArrayやNSMutableArrayに変換する関数を見つけてきて、そいつを使っています(というか、ADC内のコラムで見掛けたモノです)


static NSMutableArray* MakeMutableArrayCopy(NSArray *array);
static NSMutableDictionary* MakeMutableDictionaryCopy(NSDictionary *dict);

NSMutableArray* MakeMutableArrayCopy(NSArray *array)
{
    id  copy;
    int i;
   
    // Make copy
    copy = [[NSMutableArray alloc] initWithArray:array copyItems:YES];
    [copy autorelease];
   
    // Enumerate object
    for (i = 0; i < [copy count]; i++) {
        id    object;
       
        object = [copy objectAtIndex:i];
        if ([object isKindOfClass:[NSArray class]]) {
            [copy replaceObjectAtIndex:i
                            withObject:MakeMutableArrayCopy(object)];
        }
        else if ([object isKindOfClass:[NSDictionary class]]) {
            [copy replaceObjectAtIndex:i
                            withObject:MakeMutableDictionaryCopy(object)];
        }
    }
   
    return copy;
}

NSMutableDictionary* MakeMutableDictionaryCopy(NSDictionary *dict)
{
    id copy;

    // Make copy
    copy = [[NSMutableDictionary alloc] initWithDictionary:dict copyItems:YES];
    [copy autorelease];
   
    NSArray *array = [copy allKeys];
    for(id key in array)
    {
        id object = [copy objectForKey:key];
        if ([object isKindOfClass:[NSArray class]])
        {
            [copy setObject:MakeMutableArrayCopy(object) forKey:key];
        }
        else
        if ([object isKindOfClass:[NSDictionary class]])
        {
            [copy setObject:MakeMutableDictionaryCopy(object) forKey:key];
        }
    }
   
    return copy;
}

id MakeMutablePlistCopy(id plist)
{
    id copyPlist;
   
    if ([plist isKindOfClass:[NSArray class]]) {
        copyPlist = MakeMutableArrayCopy(plist);
    }
    else if ([plist isKindOfClass:[NSDictionary class]]) {
        copyPlist = MakeMutableDictionaryCopy(plist);
    }
    else {
        copyPlist = [plist copy];
    }
   
    return copyPlist;
}

人様のコードに少し手を入れた程度なので、見辛いのはご容赦ください(笑)


NSDictionary *dict;    // ←TouchJSONでパースされたデータ
NSMutableDictionary *hoge = MakeMutablePlistCopy(dict);

使う時はたったこんだけ。NSDictionaryだろうがNSArrayだろうが、深くネストされたNSDictionaryやNSArrayも含めてみんなまとめてNSMutable~ に変換してくれます。超便利!再帰で処理してるので、処理の流れを追っかけてみるのも勉強になるでしょう。

戻り値はautorelease属性なので、保持する時はretainしてください。

スッキリ!

仕様は「あえて」冷たく振る舞う。

photo1集中モードの時は、ご飯はとにかくエネルギー補給ができればいいという感じ。

そんな中で見つけたんが、セブンイレブンのクリームパン。なんか、お手本みたいなお上品な味。なにげにプチブーム。


こないだ導入した、iPhone向けJSONパーサー「TouchJSON1.0.7」。
挙動が違ってる…?

{
    "hoge": {
        "fuga": 1,
        "foo": "test",
        "bar": [ 0, 1, 2, ],
    },
}

これ、本来なら読み込ませるとパースエラーになります。そう、最後の要素のカンマはJSONの仕様的にNGなんだよね。でもそれがエラーにならず、正常にパースされる。…?


{
    "hoge": {
        "fuga": 1,
        "foo": "test",
        "bar": [ 0, 1, 2 ]
    }
}

本来はこう書きます。

この仕様、頻繁に要素が追加されるデータだと、ついつい最後のカンマを放置してエラー…みたいな。ずっと昔のCで、配列や構造体の最後の要素のカンマがついたまんまコンパイルするとエラーになるのとおんなじ感覚。
まあでも仕様だし、しょーがないや、と思ってましたが、もしかして「しんどくね?」という声に応えて修正してくれたんかしらん?

でもこれで慣れてしまうと、JSONデータの可搬性は落ちるよなー。他の厳密なJSONパーサーを通すとエラーになるんだから。


一度決めた仕様って、なにげにちゃんと守ってないと思わぬところでハマる事があって、ゲーム制作の現場でもよく騒ぎになってました。

あるとき、正の値しか扱わないパラメーターがあって、負の値の方に特別な意味を与えた所…プランナーから「マジっすか!」みたいにツッコまれた。
詳しく聞いてみたら、負の値が無視されるのを利用してトリッキーな事をしてたんだって。そりゃ変更されたらしんどいわな…という話で別にパラメーターを追加する事に。

パラメーターを追加する事で、それを編集するエディタやら初期化処理やら、その他思わぬコストが掛ってしまったんですが…まあしゃーない感じ。

HTMLみたいな世の中に広く広まってる規格の修正・拡張作業なんて、想像しただけでもお腹が痛くなります(笑)

TouchJSON 1.0.7導入記

photo部長お気に入りのJSONパーサーTouchJSON

「touch」というだけあって、iPhoneで動かす事を前提にObjective-Cでシンプルに書かれています。

それが昨年末に1.0.7にバージョンアップされてたんでさっそく導入。今進行中のプロジェクトが完成に近いので導入をためらいましたが、エイヤっと(ホントはダメ)

photo最新版Xcodeだとプロジェクトのテンプレートに「Cocoa Touch Static Library」があるので、それをつかってセットアップ。配布されているファイルにXcode用のプロジェクトファイルも含まれてますがそれはスルー。

テンプレートからプロジェクトを作成したら、Source以下のソースとヘッダを丸ごとプロジェクトに追加して準備完了。シミュレーター向けやら実機向けやらDebugやらReleaseやらと構成を変えて、都合4回ビルド。

すると、build以下のDebug-iphoneosやRelease-iphonesimulatorにlibTouchJSON.aというライブラリファイルが出来あがっていると思います。あとはこいつを自分のプロジェクトでリンクすれば良い訳なのですが…後々、複数のライブラリを使う事を考えてヘッダとライブラリファイルは一か所にまとめる事にします。

たとえば ~/Lib/Header に .h ファイルを、 ~/Lib/Library に .aファイルを置くとすると、

CJSONDeserializer.h と CJSONSerializer.h を ~/Lib/Header にコピー。
build以下の libTouchJSON.a の格納されているフォルダを、フォルダごと ~/Lib/Library にコピー。で、自分のプロジェクトの設定->ビルドで、

ヘッダ検索パス ~/Lib/Header
ライブラリ検索パス  ~/Lib/Library/$(BUILD_STYLE)-$(PLATFORM_NAME)
他のリンカフラグ -lTouchJSON

と設定してやれば、ビルド構成ごとに適したライブラリをリンクしてくれるので便利。ホントはヘッダファイルやライブラリファイルのコピーまでをXcodeでやって欲しいのですが、やりかたがわかりませーん(笑)


JSONファイルの読み/書きは至って簡単。ここを参考にすれば問題ないでしょう。JSONの書き方はここ


{
    "hoge": 10,
    "hogehoge": 100.0,
    "hogehogehoge": "hoge",
    "fuga": [ 1, 2, 3 ]
}

JSONデータは上記みたく、ルート構成が連想配列になってるのをNSDictionaryとして取り出すのみかと思ってましたが、

[
    10, 100.0, "test"
]

上記みたく、ルート構成が配列になってるのをNSArrayとして取り出せる事が判明。い、いつの間に…!

READMEには書かれてませんが、ヘッダを見るとNSDictionary用とNSArray用にメソッドが用意されてます。GJ!

- (id)deserialize:(NSData *)inData error:(NSError **)outError;
ついでに、汎用性を求めるなら、このメソッドを使う感じで。


JSONはXMLと比べて人様の手での修正が簡単なので、部長的にもしばらく使い続けていこうと思ってます。「他の誰か」に編集をお願いする時の事を考えると、XMLは説明できる自信が無い…。でもJSONなら仕組みも単純だし、いろんな言語上で実装されているからね。

Enjoy It!!

飲みの席とEmacsでJSON

さっきまで高濱さんと鶴岡さんとで、こんな感じに飲んでました(汗)

なんつーアホ顔…。

鶴岡さんとは、ミステリーガールズの夏のイベント以来。ジャンルは違えど、ハードコア車好き三人なんで、つい車談義に突入しがち~な年越し飲みの席でした(笑)

鶴岡さん、よいお年を~。

そんで、事務所戻ってきて作業再開。まだまだー!(泣)


EmacsでJSON編集~完結編

EmacsでJSONを扱う場合、こなへん javascript.el が一般的みたいなので導入してみた…けど、JSON的には正しくてもJavascript的にNGな書き方が引っ掛かって、インデントでエラーを吐かれる。

{
    "test": 10,
    "sample": "test",
    "pos": [ 10, 10 ]
}

↑こういうふうに書いただけのjsonファイル。どの行でTABを押しても「引数がnilです」的なエラーが出てインデントしてくんない。

ので、javascript.el を解析して修正。ついでに "[" と "]" 入力も自動インデントの対象になるよう改造。


(when javascript-auto-indent-flag
  (mapc (lambda (key)
      (define-key javascript-mode-map key 'javascript-insert-and-indent))
    '("{" "}" "(" ")" ":" ";" "," "[" "]"))) ; modifyed for json

↑95行目付近(.emacsに書いた方がよかったかも)


(if(> (point) 1)        ; modifyed for json
  (when (= (char-before) ?\)) (backward-list)))

↑431行目付近

んで、バイトコンパイルして完成。おお~手前味噌ながら、そうしてほしかった感じでインデントしてくれる!超便利。


(defun byte-compile-this-file ()
  "Compile current-buffer-file of Lisp into a file of byte code."
  (interactive)
  (byte-compile-file buffer-file-name t))

↑ついでに、どちらかで見つけた「カレントバッファをバイトコンパイル」するelisp。これも超便利。

まだ名前で管理してないの?

photoたとえばシューティングゲームを作ってて、敵の基本データを構成するJSONを用意するとするよね。

{
    "enemy": [
        [ "enemy_blue", 1, 5.0, 1 ],
        [ "enemy_red", 2, 2.5, 1 ],
        [ "enemy_green", 1, 1.5, 5 ]
    ]
}


んで、取り出すプログラムはこんな感じ?

NSArray *array = [json_dict objectForKey:@"enemy"];
NSArray *enemy = [array objectAtIndex:0];
int bullet_power = [[enemy objectAtIndex:1] intValue];

えーっと…シールドの値を書き変えたいんだけど、どれを触ればいいんだい?!
オーケーわかった!じゃあちょっと書き換えてみようか。

{
    "enemy_blue": {
        "graphic": "enemy_blue",
        "bullet_power": 1,
        "speed": 5.0,
        "shield": 1
    },
    "enemy_red": {
        "graphic": "enemy_red",
        "bullet_power": 2,
        "speed": 2.5,
        "shield": 1
    },
    "enemy_green": {
        "graphic": "enemy_green",
        "bullet_power": 1,
        "speed": 1.5,
        "shield": 5
    }
}


こうやってアクセスします。

NSDictionary *enemy = [json_dict objectForKey:@"enemy_red"];
int bullet_power = [[enemy objectForKey:@"bullet_power"] intValue];


そう。敵のデータを配列で用意するんじゃなくって、辞書配列を使って用意するって事!

こうすると、「enemy_greenは配列の3番目にあって…」って事を知る必要はないし、誰かが途中にデータを挿入してプログラムが動かなくなる…なんてトラブルからも解放されるよね。
それに…どんなパラメータで構成されてるかが一目瞭然だ!(これ重要)

配列の場合インデックスを使って配列の範囲の外へ簡単にアクセスできてしまう危うさがあるけど、辞書配列の場合はNULLを返してくるだけだから、エラーチェックも確実。


ゲーム開発も、いろんな人が関わってくるとデータ管理との戦いになってくるかんね。有能なプログラマは臨機応変にスマートかつ管理コストの低い手法を提案できるもんです。てか、そういう環境を自分で作ってる。

ちょっと前に関わったプロジェクトで、画像データを更新するのにバイナリエディタを使わないといけないってのに遭遇してキレそうになったのを思い出した(結局キレた)

JSON with iPhone

photoゲームを作ってると、ハイスコアを保存したくなったり、ロープレだったら主人公のパラメータを保存しといて「続き」ができるようにしたりと、いわゆる「セーブデータ」を扱う事も出てきます。

さいきんは「シリアライズ」と呼ぶそうなんですが…PSの開発をしている時なんかは、乱暴にも構造体のデータをまるっとメモリーカードに書き出しておしまい。てな具合で、極めて原始的な手続きで済ませてました。

でもこれだと、構造体の中がほんのちょっとでも変わるともうアウト!
規模の小さいゲームなら「もっかい最初からプレイして」も通じるけど、ドラクエとかFF級の開発でそれはありえないよね。

っていうんでみんな最近はどーしてるかっていうと、XMLやらYAMLやらJSONやらの汎用的なテキストフォーマットを使ってるみたいです(詳しくはグーグル先生に聞いてみよう!)

そんで、そのシリアライズ機能。iPhoneの開発環境では標準で入ってます。

//書き出し
NSArray *array;
[array writeToFile:path atomically:YES];

//読み込み
(NSArray *)array = [NSArray arrayWithContentsOfFile:parh];

こんだけ。
なんつー便利な。でもファイルフォーマットがXML…手作業でファイルを触りたい派にはちょっとこれは厳しい的な。

んで、いろいろ調べてみた結果、自分的に可読性が良好で構造も単純なJSONがいいだろうって事で、iPhoneで使えるライブラリを探してみたよ。

JSONの仕様
http://json.org/json-ja.html

TouchJSON
http://code.google.com/p/touchcode/wiki/TouchJSON

まぁ使い方はページ内の「TouchJSONHowTo」を読んで頂くとして…
こんな感じでつかいます。

#import <CJSONDeserializer.h>

NSStringEncoding encoding = NSUTF8StringEncoding;
NSString *text = [NSString stringWithContentsOfFile:path usedEncoding:&encoding error:nil];
NSData *json = [text dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSDictionary *dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:json error:nil];

そしたらあとはもう、

NSNumber hoge = [dict objectForKey:@"hoge"];
NSString hoge = [dict objectForKey:@"hoge"];
NSArray hoge = [dict objectForKey:@"hoge"];
NSDictionary hoge = [dict objectForKey:@"hoge"];

とかってデータを取り出すだけ。便利!
ただし、配列だけのJSONだと読み込めないのが非常に残念。

[ 1, 2, 3, 4, 5 ]
↑これだと読み込めない

{ "hoge":[ 1, 2, 3, 4, 5 ] }
↑これならオッケー


書き出す時は、こんな感じ。

#import <CJSONSerializer.h>

NSDictionary *dict;
NSString *jsonString = [[CJSONSerializer serializer] serializeObject:dict];
NSStringEncoding encoding = NSUTF8StringEncoding;
[jsonString writeToFile:path atomically:YES encoding:encoding error:nil];

いいね!


そういや Snow Leopard って、64bit化されてんのね…
「Xcodeについて」でバージョン見た時に「64-bit」って書いてあってビックリ!

MicrosoftがOSの64bit化で四苦八苦してるなか、Appleはどんどん先をゆくなぁ…


ところで64bitってナニがスゴイの?
記事検索
電子書籍発売中

「チュートリアル形式で始めるOpenAL」
サウンド怖くない。C++による8つのチュートリアルで始めるOpenALプログラミング。さああなたも、自作アプリに魅力的な音効を添えてみませんか??
⇒Kindle版 ⇒iBooks版


「iPhoneアプリ『ういろう』のレシピ」
ゲームってどうやって作ってるの?? 拙アプリ『ういろう』の製作過程を本にまとめました。もちろんソースコードつき
⇒Kindle版 ⇒iBooks版


『チュートリアル形式で始めるOpenGL[2D編]』
OpenGL怖くない。C++による16のチュートリアルで始めるOpenGLプログラミング[2D編]。さああなたも、ゲーム作りを始めてみませんか?
⇒Kindle版 ⇒iBooks版
自作ゲーム配信中

『Puzzle & Monarch』
「君主候補となって国作り!! ただし制限時間は90秒。」森を作って道をつないで...あなただけの国を作ってみませんか??
⇒AppStore


『BRICK & TRIP』
咄嗟の判断に、あなたの指先はついてこれるか?! 爽快フリックアクション!! 様々な難関をくぐり抜けて旅の終着点を目指そう!!
⇒AppStore


『ういろう』
名古屋土産ういろうがiPhoneで大活躍?! 白ういろうを守れるのはあなただけ。ひゅーん、ぼよよーん!!
⇒AppStore ⇒LITE版


『こなへん』
ヒマラヤ山脈、大西洋、世界で一番深い湖… それって地球のどこにあるのか知ってるかな?『全方位直感地理クイズ』という新ジャンルに挑戦!あ、それ。地球をくーるくるw
⇒AppStore ⇒LITE版


『GEOSPOT』
ヒマラヤ山脈、大西洋、世界で一番深い湖… それって地球のどこにあるのか知ってるかな?『全方位直感地理クイズ』という新ジャンルに挑戦!あ、それ。地球をくーるくるw
⇒Windows ⇒Mac


『TieGunner』
マウス片手に大宇宙へ飛び立とう!『しっぽシューティング』というジャンルを作って頂きました^^; WinでもMacでも動きます。ソースもあるでよw
⇒Windows ⇒Mac
QRコード
QRコード
  • ライブドアブログ