NSCache介绍

`之前在做项目需求(需要缓存几百个头像文件和用户数据)时候用到了一种新的缓存方式,之前是用NSMutableDictionary来缓存,后来了解到了转用NSCache来缓存。但是Dict不会自动删除多余的,会占用很多空间,如下引用所说

我们通常用使用缓存来临时存储短时间使用但创建昂贵的对象。重用这些对象可以优化性能,因为它们的值不需要重新计算。另外一方面,这些对象对于程序来说不是紧要的,在内存紧张时会被丢弃。如果对象被丢弃了,则下次使用时需要重新计算。

NSCache简介

NSCache是苹果官方提供的缓存类,用法与NSMutableDictionary的用法很相似,在AFNetworking和SDWebImage中,使用它来管理缓存。
NSCache在系统内存很低时,会自动释放一些对象(出自苹果官方文档,不过在模拟器中模拟内存警告时,不会做缓存的清理动作) 为了确保接收到内存警告时能够真正释放内存,最好调用一下removeAllObjects方法。
NScache是线程安全的,在多线程操作中,不需要对Cache加锁。
NScache的key只是做强引用,不需要实现NScopying协议。

NSCache和NSMutableDictionary的区别

当一个key-value对在缓存中时,缓存维护它的一个强引用。存储在NSCache中的通用数据类型通常是实现了NSDiscardableContent协议的对象。在缓存中存储这类对象是有好处的,因为当不再需要它时,可以丢弃这些内容,以节省内存。默认情况下,缓存中的NSDiscardableContent对象在其内容被丢弃时,会被移除出缓存,尽管我们可以改变这种缓存策略。如果一个NSDiscardableContent被放进缓存,则在对象被移除时,缓存会调用discardContentIfPossible方法。

NSCache与可变集合NSMutableDictionary有几点不同:

1.NSCache类结合了各种自动删除策略,以确保不会占用过多的系统内存。如果其它应用需要内存时,系统自动执行这些策略。当调用这些策略时,会从缓存中删除一些对象,以最大限度减少内存的占用。
2.NSCache是线程安全的,我们可以在不同的线程中添加、删除和查询缓存中的对象,而不需要锁定缓存区域。
3.不像NSMutableDictionary对象,一个缓存对象不会拷贝key对象。
这些特性对于NSCache类来说是必须的,因为在需要释放内存时,缓存必须异步地在幕后决定去自动修改自身。

NSCache的使用

缓存限制

系统提供了两个属性来设置缓存上限,

默认值为0,表示不限制数量。但需要注意的是,这不是一个严格的限制。如果缓存的数量超过这个数量,缓存中的一个对象可能会被立即丢弃、或者稍后、也可能永远不会,具体依赖于缓存的实现细节。
在后续的测试中,按顺序添加的缓存,会在超出后,按照顺序丢弃删除。
@property NSUInteger countLimit;    // limits are imprecise/not strict
默认值是0,表示没有限制。当我们添加一个对象到缓存中时,我们可以为其指定一个消耗(cost),如对象的字节大小。如果添加这个对象到缓存导致缓存总的消耗超过totalCostLimit的值,则缓存会自动丢弃一些对象,直到总消耗低于totalCostLimit值。不过被丢弃的对象的顺序无法保证。
一般不建议这一方式来设定缓存限制。
@property NSUInteger totalCostLimit;    // limits are imprecise/not strict
该方法对应的存的方法是- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
这个消耗值用于计算缓存中所有对象的一个消耗总和。当内存受限或者总消耗超过了限定的最大总消耗,则缓存应该开启一个丢弃过程以移除一些对象。不过,这个过程不能保证被丢弃对象的顺序。其结果是,如果我们试图操作这个消耗值来实现一些特殊的行为,则后果可能会损害我们的程序。通常情况下,这个消耗值是对象的字节大小。如果这些信息不是现成的,则我们不应该去计算它,因为这样会使增加使用缓存的成本。如果我们没有可用的值传递,则直接传递0,或者是使用-setObject:forKey:方法,这个方法不需要传入一个消耗值。
存取方法

NSCache提供了若干key-value的存取方法,分别是

- (nullable ObjectType)objectForKey:(KeyType)key;
- (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost
- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
- (void)removeObjectForKey:(KeyType)key;

- (void)removeAllObjects;
NSCacheDelegate代理

NSCache还有一个代理协议
@property (nullable, assign) id<NSCacheDelegate> delegate;
协议需要实现的方法是
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
意在 缓存将要删除对象时调用,不能在此方法中修改缓存。仅仅用于后台的打印,以便于程序员的测试。

???收到内存警告后无法再加入到cache中?
查阅到有资料称:当收到内存警告,调用removeAllObjects 之后,无法再次往缓存池中添加数据.还没找到制造内存警告的方法,所以还没有验证([self ***]方法似乎没有效果.

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,249评论 0 9
  • NSCache 是一个容器类,类似于NSDIctionary,通过key-value 形式存储和查询值,用于临时存...
    小赢一场阅读 1,116评论 0 0
  • 你要知道的NSCache都在这里 转载请注明出处 http://www.jianshu.com/p/2392268...
    WWWWDotPNG阅读 12,309评论 13 95
  • 今天研究SDWebimage发现,里面使用了NSCache的一个方法setObject:forKey:cost:首...
    RealSlimAlan阅读 2,085评论 1 6
  • 一夜无眠。 不知道是被外面持续不断地鞭炮声影响,还是被自己的心魔所干扰,一夜反反复复地打滚,来来回回地翻身,明明困...
    实心实意阅读 411评论 2 4
  • 马上2018年,定下一个小目标,每天手绘一幅,哪怕是一个拇指画。完整的小作品,保持着画画的手感和灵性。然后用可支配...
    柠萌Dream阅读 221评论 0 2
  • Java代码在编译后变成字节码,字节码被类加载器加载到JVM,JVM解析执行字节码,转化为机器码在CPU上执行,J...
    luoxn28阅读 578评论 0 2
  • 早就有人要我记住 这个是妈妈 那个是爸爸 这是三字经 那是5块钱纸币 虽然搞不清楚为什么 但我们记住了 很多这个和...
    前帮主阅读 111评论 0 0