1、简介
A mutable collection you use to temporarily store transient key-value pairs that are subject to eviction when resources are low.
点击查看官方详细简介
NSCache 是苹果官方提供的缓存类,用法与 NSMutableDictionary 的用法很相似,在 SDWebImage 和 AFNetworking 中,使用它来管理缓存。
同样是以 key-value 的形式进行存储,NSCache 与 NSMutableDictionary 等集合类的区别或者说优势有:
1、 NSCache在系统内存很低时会自动释放对象(在模拟器进行演示的时候不会释放),不需要手动干预,如果是自定义实现需要监听内存状态然后做进一步的删除对象的操作。
2、 NSCache是线程安全的,在进行多线程操作时,不需要进行加锁。而使用NSMutableDictionary自定义实现缓存时需要考虑加锁和释放锁,NSCache已经帮我们做好了这一步。
3、NSCache的Key只是对对象进行了Strong引用,而非拷贝,所以key不需要实现NSCopying协议。
2、属性和方法
(1)属性
/*
NSCache能够占用的消耗?的限制
当NSCache缓存的对象的总cost值大于这个值则会自动释放一部分对象直到占用小于该值
非严格限制意味着如果保存的对象超出这个大小也不一定会被删除
这个值就是与前面setObject:forKey:cost:方法对应
*/
@property NSUInteger totalCostLimit; // limits are imprecise/not strict
/*
缓存能够保存的key-value个数的最大数量
当保存的数量大于该值就会被自动释放
非严格限制意味着如果超出了这个数量也不一定会被删除
*/
@property NSUInteger countLimit; // limits are imprecise/not strict
/*
这个值与NSDiscardableContent协议有关,默认为YES
当一个类实现了该协议,并且这个类的对象不再被使用时意味着可以被释放
*/
@property BOOL evictsObjectsWithDiscardedContent;
(2)方法
//通过key获取value,类似于字典中通过key取value的操作
- (nullable ObjectType)objectForKey:(KeyType)key;
//设置key、value
- (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost
/*
设置key、value
cost表示obj这个value对象的占用的消耗?可以自行设置每个需要添加进缓存的对象的cost值
这个值与后面的totalCostLimit对应,如果添加进缓存的cost总值大于totalCostLimit就会自动进行删除
感觉在实际开发中直接使用setObject:forKey:方法就可以解决问题了
*/
- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
//根据key删除value对象
- (void)removeObjectForKey:(KeyType)key;
//删除保存的所有的key-value
- (void)removeAllObjects;
(3)协议
//NSCacheDelegate协议
@protocol NSCacheDelegate <nsobject>
@optional
//上述协议只有这一个方法,缓存中的一个对象即将被删除时被回调
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
@end
3、例子
@interface ViewController () <NSCacheDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 创建一个NSCache缓存对象
NSCache *cache = [[NSCache alloc] init];
// 设置缓存中的对象个数最大为5个
[cache setCountLimit:5];
// 设置代理
cache.delegate = self;
// 遍历十次 将字符串类型的对象添加进缓存中
for (int i = 0; i < 10; i++) {
[cache setObject:[NSString stringWithFormat:@"Hello%d", i] forKey:[NSString stringWithFormat:@"World%d", i]];
NSLog(@"Add key:%@ value:%@ to Cache", [NSString stringWithFormat:@"Hello%d", i], [NSString stringWithFormat:@"World%d", i]);
}
// 获取缓存
for (int i = 0; i < 10; i++) {
NSLog(@"Get value:%@ for key:%@", [cache objectForKey:[NSString stringWithFormat:@"World%d", i]], [NSString stringWithFormat:@"World%d", i]);
}
// 清除所有缓存
[cache removeAllObjects];
}
//当缓存中的一个对象即将被删除时会回调该方法
- (void)cache:(NSCache *)cache willEvictObject:(id)obj {
NSLog(@"Remove Object %@", obj);
}
打印的结果为:
Add key:Hello0 value:World0 to Cache
Add key:Hello1 value:World1 to Cache
Add key:Hello2 value:World2 to Cache
Add key:Hello3 value:World3 to Cache
Add key:Hello4 value:World4 to Cache
Remove Object Hello0
Add key:Hello5 value:World5 to Cache
Remove Object Hello1
Add key:Hello6 value:World6 to Cache
Remove Object Hello2
Add key:Hello7 value:World7 to Cache
Remove Object Hello3
Add key:Hello8 value:World8 to Cache
Remove Object Hello4
Add key:Hello9 value:World9 to Cache
Get value:(null) for key:World0
Get value:(null) for key:World1
Get value:(null) for key:World2
Get value:(null) for key:World3
Get value:(null) for key:World4
Get value:Hello5 for key:World5
Get value:Hello6 for key:World6
Get value:Hello7 for key:World7
Get value:Hello8 for key:World8
Get value:Hello9 for key:World9
Remove Object Hello5
Remove Object Hello6
Remove Object Hello7
Remove Object Hello8
Remove Object Hello9
上面的代码创建了一个NSCache对象,设置了其最大可缓存对象的个数为5个,从输出可以看出,当我们要添加第六个对象时NSCache自动删除了我们添加的第一个对象并触发了NSCacheDelegate的回调方法,添加第七个时也是同样的,删除了缓存中的一个对象才能添加进去。
在第二个for循环中,我们通过key取出所有的缓存对象,前五个对象取出都为nil,因为在添加后面的对象时前面的被删除了,所以,当我们从缓存中获取对象时一定要判断是否为空,我们无法保证缓存中的某个对象不会被删除。
接着调用了NSCache的removeAllObjects方法,一旦调用该方法,NSCache就会将其中保存的所有对象都释放掉,所以,可以看到调用该方法后NSCacheDelegate的回调方法执行了五次,将NSCache中的所有缓存对象都清空了。
当点击home键,程序进入后台后,可以发现NSCacheDelegate的回调函数触发了,所以,当程序进入后台,NSCache对象会自动释放所有的对象。如果在模拟器上模拟内存警告,也可以发现NSCache会释放所有的对象。所以NSCache删除缓存中的对象会在以下情形中发生:
1、NSCache缓存对象自身被释放
2、手动调用removeObjectForKey:方法
3、手动调用removeAllObjects
4、缓存中对象的个数大于countLimit,或,缓存中对象的总cost
5、值大于totalCostLimit
6、程序进入后台后
7、收到[系统]的内存警告
以上参考了以下文章:
iOS缓存 NSCache详解及SDWebImage缓存策略源码分析
网友评论