图片缓存是SDWebImage最重要,最常用的功能。用户浏览过的图片会默认缓存在cache与磁盘上,缓存默认保存一星期时间。也就是说在无网络的环境下,用户依然能够通过缓存查看到一星期之内的已经浏览过的图片。很强大,但是它也是个吃磁盘的怪物,一张图片数据实际上会在磁盘上保存两份,可以想象磁盘可用空间减小的速度有多快。建议使用SDWebImage的开发者给用户提供一个清除缓存的功能,使用户能够及时的清理磁盘,避免App被卸载的悲剧。
SDWebImageManager
SDWebImageManager类是SDWebImage的核心类,它管理着图片的下一步具体行为:
- 从缓存中查找图片
- 图片存在,显示图片
- 图片不存在,下载图片
- 下载完成后,将图片添加到缓存,显示图片
在这个类中,将图片缓存功能与上一章所说的图片下载功能关联到了一起,构成了SDWebImage的主体图片显示逻辑。
SDImageCache
图片缓存的代码主体类是SDImagaCache,毫无疑问该类的主要代码逻辑就是增、删、查、改等操作。这里我们重点来看下面这几个关键点:
图片标识
缓存图片首先要解决的问题就是通过什么来区分一张张的图片,我们自然而然的会想到图片的URL链接。是的,SDWebImage也是这样干的:
SDWebImageManager获得图片缓存使用的key
SDImageCache保存图片到磁盘使用的名称
与我们设想不同的一点是,它会到图片的URL作MD5运算得到新的文件名,使用该名称来保存图片,避免URL名称过长导致异常。
查询缓存图片
先从cache中查找图片,没有找到再尝试从磁盘中查找。
UIImage* = [self imageFromMemoryCacheForKey:key];
if(image){
doneBlock(image, SDImageCacheTypeMemory);
return nil;
}
从磁盘中查找时使用了多线程,因此整个查找方法的返回会为一个NSOperation对象。
NSOperation* operation = [NSOperation new];
dispatch_async(self.ioQueue, ^{
if(operation.isCancelled){
return;
}
@autoreleasepool{
UIImage* diskImage = [self diskImageForKey:key];
if(diskImage && self.shouldCacheImagesInMemory){
NSUInteger cost = SDCacheCostForImage(diskImage);
[self.memCache setObject:diskImage forKey:key cost:cost];
}
dispatch_async(dispatch_get_main_queue(), ^{
doneBlock(diskImage, SDImageCacheTypeDisk);
});
}
});
return operation;
这里要注意的一点是,ioQueue是一个serial queue,所有对磁盘缓存图片的增、删、改、查操作都被放到这个队列中排队,保证了多线程操作的安全。
吐嘈
不是太喜欢整个工程里全是Block的代码风格,这让我感觉到恐慌。而在OC里面,一但一个环节使用了Block,其后所有环节可能都需要使用,且基本都是在前一环节Block的基础上的进一步封装,很容易就让阅读者陷入困境。有什么好的方案能改进这种情形吗?
网友评论