私は自分のアプリでこの問題を数か月にわたって輪になって回っています。私は多くの自作のソリューションを試しましたが、ここで私が取り組んでいることを説明しますが、誰かが私が見逃したより良い解決策を提案してくれることを願っています.
基本的な問題は次のとおりです。アプリからいつでもアクセスする必要があるアイテムが (潜在的に) 数千あります。NSMutableDictionary は通常、各項目を表すための最初のアプローチです。各項目には数個から数百個のプロパティがある可能性があるためです。しかし、残りの要件は物事を毛むくじゃらにします。
- 各アイテムは、任意のスレッドから読み取られたり、書き込まれたりする可能性があります
- 各アイテムは、セッション間で取得できるようにディスクに保存する必要があります
- 非常に多くの項目 (および非常に多くのデータ) が (潜在的に) 存在するため、一度にすべてをメモリに格納すると、メモリの問題が発生する可能性があります
Apple がとても気に入っている CoreData を使用したかったのですが、多くの問題に遭遇しました。各アイテムには決定的な構造がないため、データ モデルを構造化する良い方法はありません。さらに、データのクエリにより、単一の .sqlite ファイルがボトルネックとして機能するようになりました。つまり、多くのスレッドがアイテムを一度に取得しようとすると、待機時間 (ラグ) が非常に速くなりました。
実用的な解決策がありますが、問題があります。これがコードの一部です。以下でその機能を説明します。
- (NSObject*) getValue:(NSString*)key {
@synchronized(self) {
if(!_cached_obj) { // private variable in this object
_cached_obj = [self loadFromDisk]; // simply loads the NSDictionary from a file
}
_last_access = time(nil);//don't release for a while
return [_cached_obj valueForKey:key];
}
}
- (void) setValue:(NSObject*)value forKey:(NSString*)key {
@synchronized(self) {
[self getValue:key];//ensures the cache is active
[_cached_obj setValue:value forKey:key];
_needs_save = true;
}
}
- (void) clean {
if(!_cached_obj)
return;
@synchronized(self) {
if(_needs_save)
{
[self writeToFile];//writes the cache obj to a file
_needs_save = NO;
}
NSTimeInterval elapsed = time(nil) - _last_access;
if(elapsed > 20)
{
[_cached_obj release];
_cached_obj = nil;
}
}
}
- Item からのデータが必要な場合は、getValue 関数が呼び出されます。キャッシュされたオブジェクト (NSMutableDictionary) を使用しようとします。キャッシュされたオブジェクトが NULL の場合、オブジェクトをディスクからロードしてから返します。
- setValue 関数は期待どおりに機能しますが、保存フラグも設定します
- 「クリーン」機能は、バックグラウンド スレッドによって 10 秒のタイマーで実行されます。これにより、アイテムがディスクに保存され、メモリを節約するためにデータがキャッシュから削除されます。
私のアプローチで気に入らない点は、@synchronized の使用に基づいて、セマフォを大量に待機していることです。場合によっては、これはメイン スレッドがディスクの読み取り/書き込みを待機している間にブロックされていることも意味します。これは苦痛です。
私が見逃しているより良いデータ構造またはストレージメカニズムはありますか?
ありがとう!
編集: 詳細: 「getValue」関数が返す速度は、メイン スレッドをブロックしていなくても非常に重要です。たとえば、バックグラウンド スレッドで 10,000 個のアイテムを検索しているシナリオを考えてみましょう。10k オブジェクトのそれぞれから 1 つの値を 1 回取得する必要があります。私の現在のメカニズムでは機能しますが、キャッシュされていない各オブジェクトをディスクからロードするのは時間がかかり、iPhone 4 では最大 20 秒かかります。 " しかし、おそらくデータを小さなチャンクに保存すると役立つでしょうか? たとえば、アイテム全体を辞書として保存するのではなく、個別のオブジェクトのコレクションとして保存します。