WellCached 是一个 NSCache 子类,它提供基于键的索引访问、基于时间的键过期,以及一个类似于 Rails 的 fetch
API,可以与异步源的数据一起工作。
WellCached 包含一个类 ELAWellCached
,它可以像 NSCache
一样使用
ELAWellCached *cache = [ELAWellCached new];
[cache objectForKey:@"foo"]; // nil
[cache setObject@"bar" forKey:@"foo"];
[cache objectForKey:@"foo"]; // @"bar"
只要您的键遵循 NSCopying
协议,您就可以使用类似于 NSDictionary 的基于键的索引访问语法
ELAWellCached *cache = [ELAWellCached new];
cache[@"foo"]; // nil
cache[@"foo"] = @"bar";
cache[@"foo"]; // @"bar"
与 NSCache 不同,您可以通过设置过期持续时间来自动使缓存中的对象过期
ELAWellCached *cache = [ELAWellCached cacheWithDefaultExpiringDuration:60]; // 60 seconds
cache[@"foo"] = @"bar";
// 61 seconds later:
cache["foo"]; // nil
上述缓存中的每个对象都会在默认过期时间后自动过期。您可以使用 setObject:forKey:expirationInterval:
设置每个键的过期时间来覆盖默认值,如下所示
ELAWellCached *cache = [ELAWellCached cacheWithDefaultExpiringDuration:60]; // 60 seconds
[cache setObject:@"bar" forKey:@"foo" expirationInterval:30];
// 31 seconds later
cache[@"foo"]; // nil
"fetch" API 通过传递一个块,在发生缓存缺失时为您提供了生成缓存对象的机会。这使得尝试获取缓存对象但得到缺失的情况,导致对象的再生,然后返回再生结果的场景变得更加常见。因此,而不是这个:
- (id)getExpensiveCalculation
{
id result = self.cache[@"key"];
if (result) { // if the result is cached, go ahead and return it
return result;
}
// Not in the cache, so have to regenerate it and then set it in the cache
result = [self generateExpensiveCalculation];
self.cache[@"key"] = result;
return result;
}
您可以只写这个:
- (id)getExpensiveCalculation
{
return [self.cache fetch:@"key" generateOnMiss:id^{
// This block called only if 'key' wasn't already in the cache
return [self generateExpensiveCalculation];
}]
}
在我看来,这个 API "读取" 的比上一个例子更好;它使发生了什么事情更加明显。
在上一个例子中,因为我们的大多数方法都是同步的,所以我们只需从 generateOnMiss:
块中返回它的结果,以在缓存缺失时填充我们的缓存。
如果相反,generateExpensiveCalculation
是一个异步方法,它接收一个回调,该回调返回其结果,则此方法行不通,因为 generateOnMiss:
块将在异步回调有机会运行之前完成执行。
在这种情况下,您应使用不同的方法。在这个例子中,generateExpensiveCalculation
现在是一个异步方法,这意味着顶级 getExpensiveCalculation
方法也需要基于回调和
- (void)getExpensiveCalculation:(void (^)(id))callback
{
[self.cache fetch:@"key" generateOnMissAsync:^(ELAResultCallback resultCallback) {
// This block is called if 'key' isn't already in the cache
[self generateExpensiveCalculation:^(id expensiveCalc){
// Fill the cache with the result of the expensive calculation
resultCallback(expensiveCalc);
}];
} result:^(id result) {
// This block is called with either the already cached result,
// Or the newly generated cached result
callback(result); // Returns back to whoever called getExpensiveCalculation
}];
}
同步和异步 fetch
方法都有变体,允许您传递自定义的过期持续时间。
要运行测试;克隆仓库,安装 xcpretty,并从根目录运行 rake test
,或者打开“WellCache.xcworkspace”并使用 ⌘U
运行测试目标
大多数时候,您只需要使用 NSURLCache 进行昂贵的操作缓存即可,但在一些常见情况下,您对获取数据的网络层没有太多的控制,例如使用与他们的服务器通信的第三方API库,或者例如苹果提供的路线API。
因此,Examples/WalkingDirections
中的示例项目使用WellCached
来检索和存储表格视图中每个位置的步行路线的结果。
查看MasterViewController.m
了解如何使用WellCached
。
除了Foundation外,没有其他依赖
像这样导入ELAWellCached
头文件
#import <WellCached/ELAWellCached.h>
我打算在此基础上继续提高类的线程安全性能并扩展其单元和集成测试,还将在实际应用中使用该版本,然后在推出1.0之前再交付。公共API可能会在1.0之前随时更改。在1.0时,API将视为稳定版,并遵循语义版本化。
Eric Allam, [email protected]
WellCached在MIT许可下提供。有关更多信息,请参阅LICENSE文件。
如果您想为此项目做出贡献,请fork此仓库并创建pull requests(在分支上,而不是master)。
请确保所有代码都有单元测试支持。查看Tests/WellCachedTests.m
文件以获取现有的测试。