iOS-缓存-NSCache简单实用
2019-03-25 本文已影响0人
御雪飞斐
为什么构建缓存时选用NSCache 而非NSDictionary呢?
NSCache优于NSDictionary的几点:
当系统资源将要耗尽时,NSCache具备自动删减缓冲的功能。并且还会先删减“最久未使用”的对象。
NSCache不拷贝键,而是保留键。因为并不是所有的键都遵从拷贝协议(字典的键是必须要支持拷贝协议的,有局限性)。
NSCache是线程安全的:不编写加锁代码的前提下,多个线程可以同时访问NSCache。
看一下缓存的用法:
// Network fetcher class
typedef void(^EOCNetworkFetcherCompletionHandler)(NSData *data);
@interface EOCNetworkFetcher : NSObject
- (id)initWithURL:(NSURL*)url;
- (void)startWithCompletionHandler:(EOCNetworkFetcherCompletionHandler)handler;
@end
// Class that uses the network fetcher and caches results
@interface EOCClass : NSObject
@end
@implementation EOCClass {
NSCache *_cache;
}
- (id)init {
if ((self = [super init])) {
_cache = [NSCache new];
// Cache a maximum of 100 URLs
_cache.countLimit = 100;
/**
* The size in bytes of data is used as the cost,
* so this sets a cost limit of 5MB.
*/
_cache.totalCostLimit = 5 * 1024 * 1024;
}
return self;
}
- (void)downloadDataForURL:(NSURL*)url {
NSData *cachedData = [_cache objectForKey:url];
if (cachedData) {
// Cache hit:存在缓存,读取
[self useData:cachedData];
} else {
// Cache miss:没有缓存,下载
EOCNetworkFetcher *fetcher = [[EOCNetworkFetcher alloc] initWithURL:url];
[fetcher startWithCompletionHandler:^(NSData *data){
[_cache setObject:data forKey:url cost:data.length];
[self useData:data];
}];
}
}
@end
//我们使用URL作为缓存的key,将总对象数目设置为100,将开销值设置为5MB
NSPurgeableData
NSPurgeableData是NSMutableData的子类,把它和NSCache配合使用效果很好。
因为当系统资源紧张时,可以把保存NSPurgeableData的那块内存释放掉。
如果需要访问某个NSPurgeableData对象,可以调用beginContentAccess方发,告诉它现在还不应该丢弃自己所占据的内存。
在使用完之后,调用endContentAccess方法,告诉系统在必要时可以丢弃自己所占据的内存。
上面这两个方法类似于“引用计数”递增递减的操作,也就是说,只有当“引用计数”为0的时候,才可以在将来删去它所占的内存。
- (void)downloadDataForURL:(NSURL*)url {
NSPurgeableData *cachedData = [_cache objectForKey:url];
if (cachedData) {
// 如果存在缓存,需要调用beginContentAccess方法
[cacheData beginContentAccess];
// Use the cached data
[self useData:cachedData];
// 使用后,调用endContentAccess
[cacheData endContentAccess];
} else {
//没有缓存
EOCNetworkFetcher *fetcher = [[EOCNetworkFetcher alloc] initWithURL:url];
[fetcher startWithCompletionHandler:^(NSData *data){
NSPurgeableData *purgeableData = [NSPurgeableData dataWithData:data];
[_cache setObject:purgeableData forKey:url cost:purgeableData.length];
// Don't need to beginContentAccess as it begins
// with access already marked
// Use the retrieved data
[self useData:data];
// Mark that the data may be purged now
[purgeableData endContentAccess];
}];
}
}
注:在我们可以直接拿到purgeableData的情况下需要执行beginContentAccess方法。然而,在创建purgeableData的情况下,是不需要执行beginContentAccess,因为在创建了purgeableData之后,其引用计数会自动+1;