NSCacheというキャッシュモジュールについて第43回Cocoa関西で発表してきました。
NSCacheの特徴
- スレッドセーフ
- NSDictionaryのように手動でロックする必要がない
- 格納オブジェクトの上限を決められる
- 溢れたら自動破棄
- iOSのようなメモリ制約の厳しい環境に最適
- NSDictionaryに似たインターフェイス
- Mac OS 10.6 / iOS 4.0以上で使える
具体例としては、ダウンロードした画像をオンメモリにキャッシュする際等にとても有用だと思います。同じような機能を提供してくれるOSSのモジュールは見たことがあるのですが(例えばnimbusに含まれているNIMemoryCache)こちらはOS組み込みなので手軽に使えます。
発表資料
サンプルコード
Twitter及びInstagramの画像をロードしてデモするサンプルコードは以下です。それぞれの機能を動かすには、組み込みTwitterの連携設定とInstagramのアプリケーションキーが必要になります。
http://github.com/ninjinkun/NSCacheTest
おまけ
発表後の質疑応答で、キャッシュの破棄は基本的にLRUで行われていそうだという部分に、コストを入れた場合は別のアルゴリズムで破棄が行われるのではないかという意見が出ました。一応追試をしてみましたが、コストを入れた場合でもLRUのようでした。追試のコードは以下の通りです。
int main(int argc, const char * argv[]) { @autoreleasepool { NSInteger size = 1024; NSCache *cache = [[NSCache alloc] init]; for (int i = 0; i < 100; i++) { NSData *data = [NSData dataWithBytes:malloc(size) length:size]; cache.totalCostLimit = 1000; [cache objectForKey:[NSNumber numberWithInt:10]]; // 途中で10にアクセスしてみる [cache setObject:data forKey:[NSNumber numberWithInt:i] cost:i]; } for (int i = 0; i < 100; i++) { NSData *data = [cache objectForKey:[NSNumber numberWithInt:i]]; if (data) { NSLog(@"has data #%d", i); } } } return 0; } has data #10 has data #90 has data #91 has data #92 has data #93 has data #94 has data #95 has data #96 has data #97 has data #98 has data #99
3/26 16:50追記
id:KishikawaKatsumi さんが参考になる感じの使い方をつぶやかれていたので、以下に引用します。転載許可ありがとうございます! > id:KishikawaKatsumiさん
NSCacheは僕もダウンロードした画像のメモリキャッシュに使っていて、その用途にはかなり合ってる。コストは設定しないで単純に上限だけ設定することが多い。サムネイル画像とか種類がある場合はキャッシュ自体を分けることが多い。 ninjinkun.hatenablog.com/entry/2012/03/…
— Kishikawa Katsumi (@k_katsumi) March 26, 2012
NSCacheのキャッシュを用途別に分けるってのはサムネイル画像は上限カウント100で大きな画像は上限20とかそんな感じ。コストを使うよりたぶんそっちのがシンプル簡単。
— Kishikawa Katsumi (@k_katsumi) March 26, 2012
3/30 12:10追記
3/27にid:KishikawaKatsumiさんの画像キャッシュとダウンローダーについての記事が公開されていました。反応遅れてすみません…。だいぶ参考になる内容です。
ダウンロードした画像をキャッシュするクラスの設計と実装について - 24/7 twenty-four seven
2013/12/11 追記
画像の取得はSDWebImageに任せると良いと思います。このモジュールでも内部でNSCacheが使われています。