iOSアプリで、ファイルのパスを扱う時になかなか気がつかない落とし穴がありました。
iOSアプリは、
/var/***/foo.app/
というようなディレクトリでデバイス上に配置されていますが、この***の部分はアプリケーションがアップデートされた時など、変化することがあります。
例えば、Documentsディレクトリにbar.txtのようなファイルを保存するとその絶対パスは
/var/abcdef.../foo.app/Documents/bar.txt
のような形なります。この時、このパスをNSUserDefaultsかなにかに保存しておき、アプリをアップデートした後に、NSUserDefaultsに書かれたパスを読みにいこうとすると、アプリケーションのインストールディレクトリのパスが変更されており、先ほどのファイルも
/var/012345.../foo.app/Documents/bar.txt
のような場所に移動してしまっているため、読みにいけずエラーになってしまいます。
対策
対策は一つで、絶対パスの代わりに相対パスを使う事です。残念ながらCocoaには手軽に相対パスを求める機能が用意されていないのですが、通常iOSアプリではホームディレクトリより上の階層のディレクトリにあるファイルを扱うケースは稀なので、ホームディレクトリからの相対パスを扱うようにすれば問題ありません。
シンボリックリンク
Documents/bar.txtというファイルが純粋なファイルの場合は、話は簡単なのですが、これがシンボリックリンクの場合は話が厄介です。例えば
- Documents/bar20110804.txt
- Documents/bar20110803.txt
- Documents/bar20110802.txt
というようなファイルがあったとして、このうちの最新のファイルの絶対パス
Documents/bar.txt -> /var/abcdef.../foo.app/Documents/bar20110804.txt
に向かってDocuments/bar.txtというシンボリックリンクを貼ったとすると、Documents/bar.txt自体をプログラムから参照できても、そのシンボリックリンクの参照先を開けない、という現象がおきてしまいます。
Cocoaで用意されているAPIでは相対パスでシンボリックリンクを張るのは若干手間がかかるので、素直に絶対パスで張ってしまいがちなので、注意が必要です。
結論
- アプリをアップデートするとディレクトリのパスが変わる
- パスを保存するときはなるべく相対パスで
- シンボリックリンクには要注意