Cahce一般主要有以下点需要掌握:
- cache存在哪里
- cache如何存
- cache操作
- cache管理
1.存在哪里?
从默认属性和以上两个函数可以看出,SD默认缓存图片到内存,如果显示指定toDisk,则同时缓存图片到文件中。SD使用了系统提供的NSCache作为缓存容器,NSCache一个优势就是可以依据当前内存使用情况动态调整缓存(当系统内存出现告警时,自动释放一些缓存)。在使用NSCache时,可以传递缓存对象大小用来标记。SD在这一点也做出相应的处理。具体如下
1)对NSCache类扩展,监听系统内存告警通知。当收到系统内存告警通知时,自动释放全部Cache对象。
2)NSCache缓存对象时,主动计算该对象大小。
2.如何存?
1)通过串行队列执行缓存操作,保证了FIFO操作。
2)缓存前对原始数据进行PNG转换,保证了缓存最大化。
3)未加入图片压缩处理。
3.cache操作
1. 缓存图片
- (void)storeImage:(UIImage *)image forKey:(NSString *)key;
- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk;
2. 获取缓存图片
- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock;
- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key;
- (UIImage *)imageFromDiskCacheForKey:(NSString *)key;
3. 删除缓存图片
- (void)removeImageForKey:(NSString *)key;
- (void)removeImageForKey:(NSString *)key withCompletion:(SDWebImageNoParamsBlock)completion;
- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk;
- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(SDWebImageNoParamsBlock)completion;
4. 清空缓存
- (void)clearMemory;
- (void)clearDiskOnCompletion:(SDWebImageNoParamsBlock)completion;
- (void)clearDisk;
- (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock;
- (void)cleanDisk;
4.cache管理
1. 缓存有效期处理
SD默认的缓存时间是一周。在清除过期缓存图片时,首先遍历当前缓存目录下面的所有文件,删除过期文件,再重置缓存大小。
遍历缓存目录使用下面函数:
NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey];
NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL
includingPropertiesForKeys:resourceKeys options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:NULL];
归档过期缓存:
for (NSURL *fileURL in fileEnumerator)
{
......
// 根据文件路径最后修改时间来获取内容
NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
// 判断是否过缓存期
if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) {
[urlsToDelete addObject:fileURL];
continue;
}
// 这里同时对未过期的文件根据文件大小进行归档,便以后续重置缓存.
NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
currentCacheSize += [totalAllocatedSize unsignedIntegerValue];
[cacheFiles setObject:resourceValues forKey:fileURL];
}
删除过期缓存:
for (NSURL *fileURL in urlsToDelete) {
[_fileManager removeItemAtURL:fileURL error:nil];
}
重置缓存大小:
// 依据文件修改时间,对未过期的文件进行升序排序.
NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent
usingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]];
}];
// 根据设定的缓存大小,对当前缓存进行调整,删除那些快过期的文件,使当前总的文件大小小与设定的缓存大小。
for (NSURL *fileURL in sortedFiles) {
if ([_fileManager removeItemAtURL:fileURL error:nil]) {
NSDictionary *resourceValues = cacheFiles[fileURL];
NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
currentCacheSize -= [totalAllocatedSize unsignedIntegerValue];
if (currentCacheSize < desiredCacheSize) {
break;
}
}
}
2. 系统通知处理
当收到系统内存告警通知时,对内存缓存进行处理。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(clearMemory)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
当进程终止时,对缓存文件进行处理。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(cleanDisk)
name:UIApplicationWillTerminateNotification
object:nil];
当进入后台运行时,对缓存文件进行处理。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundCleanDisk)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
SD的缓存其实没有太复杂的东西,细节处理还是比较好。NSCache确实是个好东西,不过被NSDictionary给压住了。哈哈。