几个月来,我在我的应用程序中遇到了这个问题。我尝试了许多自制的解决方案,并将解释我在这里工作的内容,但我希望有人能提出我错过的更好的解决方案。
基本问题是:我(可能)有数千个项目需要我的应用随时访问。NSMutableDictionary 通常是我表示每个项目的第一种方法,因为每个项目可能有几个到数百个属性。但是其余的要求使事情变得棘手:
- 每个项目都可能被任何线程读取或写入
- 每个项目都需要存储到磁盘,以便可以在会话之间检索
- (可能)有太多的项目(和太多的数据)一次将它们全部放在内存中可能会导致内存问题
我想使用 CoreData,因为 Apple 非常喜欢它,但我遇到了很多问题。每个 Item 都没有确定的结构,因此没有很好的方法来构建数据模型。此外,查询数据会导致单个 .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;
}
}
}
- 当我需要来自某个项目的数据时,会调用 getValue 函数。它尝试使用缓存对象(NSMutableDictionary)。如果缓存的对象为 NULL,则在返回之前从磁盘加载对象
- setValue 函数按预期工作,但也设置了保存标志
- “清洁”功能由后台线程在 10 秒计时器上运行。这负责将项目保存到磁盘并取消缓存数据以节省内存。
我不喜欢我的方法的一点是,基于我对@synchronized 的使用,信号量有很多等待。有时,这也意味着主线程在等待磁盘读/写时被阻塞,这很痛苦。
我是否缺少更好的数据结构或存储机制?
谢谢!
编辑:更多信息:“getValue”函数返回的速度也非常重要,即使它没有阻塞主线程。例如,考虑我在后台线程上搜索 10k 个项目的场景。我需要从 10k 个对象中的每一个中获取一个值一次。使用我目前的机制,它可以工作,但是从磁盘加载每个非缓存对象非常耗时,并且最终在我的 iPhone 4 上需要大约 20 秒。我知道这可能只是“我必须付出的代价。 " 但是,也许将数据存储在更小的块中会有所帮助?例如,不要将整个项目存储为字典,而是存储为不同对象的集合。