2009年1月5日月曜日

route-meの、地図画像 (Tile) のキャッシュを操作したい

  • 公式のドキュメントはこちら http://code.google.com/p/route-me/wiki/CacheConfiguration
  • キャッシュにはメモリに対するキャッシュ、ファイルを利用したキャッシュ、sqliteを利用したキャッシュの3通りがある。デフォルトではメモリに32枚、sqliteに無制限に地図画像をキャッシュするようになっている。
  • キャッシュの設定を変更するにはrouteme.plistファイルを用いる
  • route-meは内部的にsqliteを処理するためにFMDBライブラリ (http://gusmueller.com/blog/archives/2008/03/fmdb_for_iphone.html) を利用しているため、route-meを利用したプロジェクトでは何もしなくてもFMDBが使える
  • たとえば、一度OpenStreetMapで開いた地図画像のキャッシュは、地図提供元をVirtualEarthにしてもOpenStreetMapにしても残ってしまうので、一度キャッシュクリアする必要がある
  • キャッシュをまとめて削除したいときはrouteme.plist中でdb-cacheのcapacityとminimalPurgeを1にする
  • またはSQLを直接発行してZCACHEテーブルをDELETEすればよい
  • またはiPhone Simulatorのdbファイルを直接Finderから削除する (~/Library/Application Support/iPhone Simulator/User/Applications/英字の長ったらしい識別子/Documents/*.sqlite) 参考はhttp://ameblo.jp/xcc/entry-10171488747.html

route-meを使っているうちに、困った事態に遭遇しました。
最初の頃に使っていたOpenStreetMapの地図画像が、いつまでたってもVirtualEarthの地図画像に入れ替わらないんです。

ごらんの通りOpenStreetMapの地図が出ます。tileSourceはVirtualEarthになっているのに!

iPhoneシミュレータをリセットしたりアプリケーションを削除したりしましたが効果なしです。
そこで原因を調査したところ、route-meは内部的にsqliteを用いた画像データのキャッシュを持っており、このキャッシュが自動的に最新のデータと入れ替わらないのが原因であることがわかりました。
(通常キャッシュはある程度保持期間が決まっていて、保持期間を過ぎたデータは破棄するようになっていると思うのですが、route-meについては少なくとも1日2日程度の期間ではキャッシュを破棄してくれないようです)
(というかsqliteのデータベースってアプリケーションごとに/var/root/Library/アプリケーション名/以下に配置されているからアプリケーションを削除したら消えるんじゃないんですか・・・?それとも全部ゴミになって残るの?単にiPhoneシミュレータが悪い?)

そこでキャッシュを破棄する方法を調べるがてら、route-meの地図画像キャッシュを設定する方法について調べてみました。
http://code.google.com/p/route-me/wiki/CacheConfiguration
公式のドキュメントをみると、"routeme.plist"というplistファイルを作成してビルドターゲットに加えることで、地図画像キャッシュの動作を変更することができるらしいです。

こんな感じで。


こうすることで、sqliteを用いたキャッシュの中に保存されるデータ量を制限することができます。
ただし、データベースの構造をみても、キャッシュ古くなったデータを自動的に削除するような機能はないようです。そのため、毎日決まった箇所の地図データを見るようなアプリの場合は、何年たっても地図の画像データが更新されません。
このように地図の画像データが更新されない恐れがある場合には、sqliteを用いたキャッシュを利用しないように設定するのがよいと思います。


さて、これで今後のキャッシュの利用方法は設定することができましたので、いますでにキャッシュされてしまっているデータを削除しましょう。
route-meではZCACHEというテーブルの中に地図画像キャッシュデータを保存していますので、このテーブルのデータを削除すればよいです。
sqliteにはTRUNCATEが無いので、DELETE文を使ってすべてのデータを削除します。
DELETE FROM ZCACHE

参考:http://www.mail-archive.com/sqlite-users@sqlite.org/msg09144.html

また、iPhoneシミュレータ上でキャッシュを消したい場合には、以下のパスにsqliteのデータベースファイルが存在しますので、そちらを丸ごと削除すればより簡単です。
(~/Library/Application Support/iPhone Simulator/User/Applications/英字の長ったらしい識別子/Documents/*.sqlite)

さぁ削除していざチャレンジ!


・・・あの、変わってないんですけど。何で?どうして?
ログをコンソールから調べてみましたが、routeme.plistが正しく読み込まれていて、間違いなくDBへのアクセスは発生していません。
となると怪しいのは地図提供元URLへのアクセスです。ここで何らかの仕組みが働いてキャッシュされているのではないかと思って調査してみました。
すると、RMWebTileImageクラスの中にこんなソースを発見。
 NSURL *url = [NSURL URLWithString: urlStr];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSCachedURLResponse *cachedData = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];

怪しいです。怪しさ大爆発です。次回はちょっと脇道にそれて、このNSURLCacheについて調査してみようと思います。