Xcodeで、フォルダ構成を維持したままリソースをコピーする

UIWebViewがローカルのhtmlを読み込む形のアプリケーションを作成する際の話です。

通常のWebサイトと同じように、Javascriptやcss、画像などをそれぞれまとめてフォルダに入れると思います。

Xcodeでは、通常だとリソースの参照をグループ化できますが、htmlではリソースをコピーする際に、実際にフォルダを作ってその中に画像等をコピーさせる必要があります。

それをするには、リソースを追加する際の以下のダイアログで、
Create folder references for any added folders
を選択します。

folder

これで、ビルド時にフォルダが作成され、フォルダ構成を維持したままリソースがコピーされるようになります。

参考:
リソースファイルをフォルダ階層を維持しながらコピーさせる:永遠ログ

iOSシミュレータで音が鳴らない/ファイルが読み込めないことがある

いつも通りビルドしたつもりなのに、突然下記の症状が出ることがあります。

  • 音声が再生されない
  • 画像が表示されない
  • ファイルが読み込めない

特に音については、CocosDenshion(SimpleAudioEngine)の使用方法や
caf/mp3/wav/aifファイルの作成方法、
afconvertコマンドでの引数指定を間違えたのか、と思いがちです。

トリガーとなるのは、直前のクリーンとリソースファイルの登録し直しです。

原因は、
Project Navigator のプロジェクト→TARGETS→Build Phases→Copy Bundle Resources
に該当のリソースファイルが登録されていないからです。
しかしここに追加しても根本的な解決になりません。

.png以外のリソースファイルをXcodeウィンドウにドラッグアンドドロップすると、
直後の「Choose options for adding these files」ダイアログにて
Add to targetsオプションでターゲットのチェックが外れています。
(.pngファイルだと、ターゲットにデフォルトでチェックが付きます)

よって、リソースファイルが更新されてもコピーされずに以前のデータが使われていたが、
クリーンしたことでそのデータも消えてしまった、というわけです。

ドラッグアンドドロップ後のダイアログによく注意し、
ターゲットにチェックを付けるようにしましょう。

NSKeyedArchiverでデータをファイルへ保存する

iOSでデータを永続化しファイルへ保存するには、いくつか方法があるようです。ここではNSKeyedArchiverを使った方法をご紹介します。

以下のメソッドは、3つの変数を受け取り、ファイル保存までを行います。

- (void)saveToFileWithVar1:(id)var1 var2:(id)var2 var3:(id)var3
{
    NSMutableDictionary* dicToSave = [[NSMutableDictionary alloc] init];

    NSMutableArray* arrayVals = [[NSMutableArray alloc] init];
    [arrayVals addObject:[[NSDictionary alloc] initWithObjectsAndKeys:
                  var1,@"var1",var2,@"var2",var3,@"var3", nil]];
    // add to dictionary
    [dicToSave setValue:arrayVars forKey:@"vars"];

    NSNumber* value;
    // add numbers
    value = [NSNumber numberWithDouble:1.0f];
    [dicToSave setValue:value forKey:@"value1"];
    value = [NSNumber numberWithDouble:3.5f];
    [dicToSave setValue:value forKey:@"value2"];

    // save to file
    [NSKeyedArchiver archiveRootObject:dicToSave toFile:@"/path/to/file"];
    [dicToSave release];
}

ファイルに保存するのは1オブジェクトです。従って、ここでは辞書オブジェクト dicToSave の内容をファイルに保存します(N行目)。

つまり、dicToSave辞書に、保存したいデータを放り込んで行けばよいわけです。この例では、配列1つ(キーはvars)と数値2つ(キーはvalue1、value2)を放り込んでいます。

NSMutableArrayなどの配列へ、プリミティブ型を格納できないことには注意しましょう。