Xcode5から追加されたAsset Catalogの挙動をいろいろ試してみた


先日yimajoさんがQiitaへ投稿された記事「[Xcode5から追加されたAsset Catalog最大のメリット](http://qiita.com/yimajo/items/239eb68265e4ea772484)」の中で

> Asset Catalog使える環境なのに使わないのは老害

とおっしゃっていたのを見て、大変ショックを受けた私（笑）はムチを打ってAsset Catalogの挙動を調べてみる事にしたのでした（もしかして釣られた！？）。

また、すでに「Asset Catalogはアプリのアイコンや起動画面で使うと管理が楽になる」というのは国内のブログなどを見ていても明白だと思いますので、今回は通常の画像パーツを取り扱う上で何をするとどうなるかを適当に試してみる事にしました。

- Xcode 5.0.1 使用 (2013/11/15現在)

## 非RetinaとRetinaで同名ファイルを突っ込むとどうなるの？

`New Image Set`で`aaa`という名前のイメージセットを作り、1xに`000.png`、2xに`Retina/000.png`をドロップで突っ込んでみた結果がこちら。

![kobito.1384492399.517850.png](https://qiita-image-store.s3.amazonaws.com/0/31347/f973b313-a3d1-f796-b1c1-738684ec6250.png "kobito.1384492399.517850.png")

`Images.xcassets`フォルダの中に以下のようなフォルダ・ファイルが出来るようです。


![kobito.1384492621.998737.png](https://qiita-image-store.s3.amazonaws.com/0/31347/833f26e9-7e6d-f202-fa90-3b8075a7c6bb.png "kobito.1384492621.998737.png")

```json:Contents.json
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x",
      "filename" : "000.png"
    },
    {
      "idiom" : "universal",
      "scale" : "2x",
      "filename" : "000-1.png"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
```

- ドラッグ＆ドロップで登録する限り、ファイルはコピーが前提のもよう（旧方式はネットワークから持ってきた時、間違ってリンク扱いにしてしまう事もあった）。
- 同名だったら勝手にリネームされて登録される(000-1.png)。
- 元の画像ファイル名は何でもよく、JSONファイルに書かれた内容によって処理される。
- Image Set名を変えた場合はフォルダ名が変わるだけでPNGファイル名は変わらない（Image Set名と中のPNGファイル名は関連していない）。

ビルドして、バイナリがどのように配置されるのかをシミュレータで試してみたところ、てっきり`aaa.png`と`aaa@2x.png`に展開されるのかと思いきや、`Assets.car`というファイルにパッキングされているようです。

![kobito.1384493923.341885.png](https://qiita-image-store.s3.amazonaws.com/0/31347/6ea25224-14ea-06d9-d6d1-23be1a769ccf.png "kobito.1384493923.341885.png")

## 画像はどうやってロードするの？

UIImage#imageNamedを使う。

```objectivec
[UIImage imageNamed:@"aaa"];
```

imageNamedは画像がキャッシュされるという話を良く聞いていますので他に方法が無いか探してみましたが、昔のように

```objectivec
NSString *path = [[NSBundle mainBundle] pathForResource:@"aaa" ofType:@"png"];
UIImage *img = [[UIImage alloc] initWithContentsOfFile:path];
```

というような書き方では動きませんでした。
パスがうまく取得できません。
（前述のように`Assets.car`になっているからでしょうね。）

参考：http://stackoverflow.com/questions/18968352/access-asset-catalog-pathforresource

## ローカライズは可能なの？

現時点では簡単にはできないようです。
頑張れば出来るっぽいですが。
参考：http://stackoverflow.com/questions/18814801/localize-asset-catalogs

## 階層化して同名の画像名があっても大丈夫なの？


2022/05/19追記：
最近のXcodeではフォルダに対して`Provides Namespace`というオプションが付いていますので、これをオンにするとフォルダのような扱いができるようになります。
（別階層であれば同名の名前もつけることができます。読み込み時はフォルダも含めた名前を指定する必要があります。）

----

![kobito.1384500431.859906.png](https://qiita-image-store.s3.amazonaws.com/0/31347/08779eb4-cad3-4f8d-2388-65b086477c6e.png "kobito.1384500431.859906.png")

警告が出ました。

![kobito.1384500462.307341.png](https://qiita-image-store.s3.amazonaws.com/0/31347/c8ac1fcb-45c0-53a6-1952-9fb65e15cd7e.png "kobito.1384500462.307341.png")

名前の重複を回避するためにフォルダ機能を使えるかと思ったのですが、駄目みたいです。

## 外部からカタログフォルダ内を構築しても勝手に反映されるの？

`Images.xcassets`フォルダ内をfinderなどから適当にいじっても、即座にXcode側が変更を検知してくれます。

ツールを作って画像を一括処理してAsset Catalogフォルダを構築するといった手段は使えそうですね。

## おまけ

Asset Catalogを使う事で、リサイザブルな設定がIDE上でできるようです(iOS7以降のようですが)。
参考：https://developer.apple.com/library/ios/recipes/xcode_help-image_catalog-1.0/SlicinganImage/SlicinganImage.html#//apple_ref/doc/uid/TP40013303-CH4-SW1

## 感想

大量の画像リソースをImage Setとしてマウスで登録していく作業は正直苦行だと思います。

- ちなみに私が先日まで作っていたアプリで使ったPNGファイルは1000近くありました（Retina+非Retina）。

やるなら（上にも少し書きましたが）デザイナーから上がってきた画像類を、`Images.xcassets`フォルダ内へ配置（JSONファイルも作成）するように自動化するツールでも作らないとやっていられなさそうです。自動化してしまえば更新も楽ですし（まあAsset Catalogを使わない場合でもこういった自動化をしている方はいらっしゃると思いますが）。

ローカライズの対応も怪しいようですし、コンフリクトのメリットは有るのかもしれませんが、通常画像においては、メリットはそれぐらいしか無いのではないかという印象です。

もしAsset Catalog使うと今まで不便だったアレコレがこんなに良くなるぜ！ですとか、むしろこんなデメリットがあるぜ！という話がありましたら、お聞かせいただけると幸いです。