NSCache是苹果提供的一套缓存机制,在AFNetworking和SDWebImage中,使用它来管理缓存。
1、NSCache和NSMutableDictionary使用起来很相似
2、这个类是线程安全的,在多线程操作中,不需要对Cache加锁,而Mutable开发的类一般都是线程不安全的,也就是说NSMutableDictionary是线程不安全的。
3、当内存不足的时候会自动的去释放内存,所以我们从缓存中取数据的时候总要判断是否为空
4、指定缓存的限额,当缓存超出限额自动释放内存
5、键对象不会像 NSMutableDictionary 中那样被复制。NScache的key只是做强引用(键不需要实现 NSCopying 协议)。
缓存数量,默认为0,没有限制
@property NSUInteger countLimit;
缓存成本,超出上限会自动回收对象,默认为0,表示是没有限制的。
@property NSUInteger totalCostLimit;
缓存的代理方法,缓存将要删除对象时调用,我们不能在这个方法中修改缓存。只是方便我们测试的。
//当缓存被移除的时候才会去执行其实就是将要从NSCache中移除一项的时候会执行
-(void)cache:(NSCache *)cache willEvictObject:(id)obj
{
NSLog(@"缓存移除了 %@",obj);
}
当我们限制了缓存总共可以加多少条的时候,当超过了限定的条数就会移除前面的对象。就比如说我们限定了缓存的条数为5条,我们在添加第6条的时候会先移除第1条,再去添加第6条。
苹果官方解释NSCache在系统内存很低时,会自动释放对象(但模拟器演示是不会释放的)我们通过模拟器来模拟内存警告,是没有走下面这个方法的,所以我们最好还是在收到内存警告的时候进行removeAllObject
- (void)cache:(NSCache *)cache willEvictObject:(id)obj
因为这里我们模拟了内存警告,然后在touchesBegan方法中进行获取里面存储的对象还是可以获取到的。
比如说我们在viewWillAppear中写了下面的代码
-(void)viewWillAppear:(BOOL)animated
{
self.cache = [[NSCache alloc] init];
[self.cache setCountLimit:3];
self.cache.delegate = self;
[self.cache setObject:@"AA" forKey:@"BBB"];
[self.cache setObject:@"MMMM" forKey:@"CCC"];
}
然后点击模拟器的内存警告,然后在touchesBegin方法中写了下面的代码发现还是可以获取到的
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"%@",[self.cache objectForKey:@"BBB"]);
}
当收到内存警告的时候,我们调用了removeAllObjects,无法再次从Cache中添加数据,经过在其他方法中调用removeAllObjects,而不是在内存警告中调用的removeAllObjects,则是可以再次使用的,如果再内存警告中调用了removeAllObjects,我们再往里面存入数据的话,就会出现我们一存入就会被删除
如下所示在收到内存警告的方法之后调用了removeAllObjects的时候,我们再在touchesBegan方法中做存入操作,一存入就被删除了。
这里还要注意的就是在我们把应用程序切入到后台,也是会清除所有的缓存的,也就是NSCache中的所有对象。
还有一点需要注意的就是当我们设置缓存实例时如果设置了totalCostLimit,存储对象到缓存的的方法调用必然带上了cost,否则totalCostLimit是无用的。也就是说我们应该使用下面的方法
- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
包括在SDWebImage中存储图片到缓存中也是这样做的很好的印证了这一点。
其实关于这个问题,苹果的官方文档也是有所提到
If 0
, there is no total cost limit. The default value is 0
.
When you add an object to the cache, you may pass in a specified cost for the object, such as the size in bytes of the object. If adding this object to the cache causes the cache’s total cost to rise above totalCostLimit
, the cache may automatically evict objects until its total cost falls below totalCostLimit
. The order in which the cache evicts objects is not guaranteed.
This is not a strict limit, and if the cache goes over the limit, an object in the cache could be evicted instantly, at a later point in time, or possibly never, all depending on the implementation details of the cache.