SDWebImage是一个功能强大的图片缓存框架,可以实现网络图片加载和缓存。那么SDWebImage的缓存机制是如何实现的呢?缓存时间是多久?清除缓存的策略是怎样的?让我们带着这些问题,走进源码,解读SDWebImage。
SDWebImage提供一个UIImageView的分类 UIImageView+WebCache,用来加载和缓存来通关HTTP传输的图片资源。提供了缓存管理、异步下载、缓存校验等功能。
缓存机制
SDWebImage 的图片缓存采用的是 Memory 和 Disk 双重Cache机制,也就是二级缓存。SDWebImage的缓存机制可以简单概括为:第一次请求加载图片后将图片缓存在内存中,并通过md5加密将图片的url进行加密处理,加密处理后的值作为key,将图片存储在磁盘中。当再次加载图片时,先在内存缓存中寻找,如果内存中找不到图片,则在默认的磁盘中寻找,如果还是找不到,则再请求加载图片
核心类:
SDWebImageManager
SDImageCache
SDWebImageDownloader
SDWebImageDownloadOperation
缓存方法
下面通过一张框架图来解释SDWebImage的框架结构:
框架.png
最上层的UIImageView+WebCache这个类里面提供了一下几个方法来供我们进行网络图片加载等操作:
1. sd_setImageWithURL:
//图片缓存的基本代码
[self.imageView sd_setImageWithURL:imagePath];
2. sd_setImageWithURL: completed:
//用block 可以在图片加载完成之后做些事情
[self.imageView sd_setImageWithURL:imagePath completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL)
{
NSLog(@"图片加载完成之后可以在这里做些事情");
}];
3. sd_setImageWithURL: placeholderImage:
//给一张默认图片,先使用默认图片,当图片加载完成后再替换
[self.imageView sd_setImageWithURL:imagePath placeholderImage:[UIImage imageNamed:@"default"]];
4. sd_setImageWithURL: placeholderImage: completed:
//使用默认图片,而且用block 在完成后做一些事情
[self.imageView sd_setImageWithURL:imagePath placeholderImage:[UIImage imageNamed:@"default"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL)
{
NSLog(@"图片加载完成后做的事情");
}];
5. sd_setImageWithURL: placeholderImage: options:
//options 选择方式
[self.imageView sd_setImageWithURL:imagePath placeholderImage:[UIImage imageNamed:@"default"] options:SDWebImageRetryFailed];
其中,除了方法5,其他的方法都是综合存储,也就是内存缓存和磁盘缓存结合的方式。方法5增加了options用来满足不同需求的缓存方式。
下面我们看一下SDWebImage为我们提供的options:
/**
* 默认情况下,当URL未能下载时,URL将被列入黑名单,因此库将不会继续尝试。
* 此标志禁用此黑名单。*
*/
SDWebImageRetryFailed = 1 << 0,
/**
* 默认情况下,在UI交互期间启动图像下载,此标志禁用此功能,
* 例如,导致UIScrollView减速下载延迟。
*/
SDWebImageLowPriority = 1 << 1,
/**
* 下载完成后,此标志禁用磁盘缓存,仅缓存在内存中
*/
SDWebImageCacheMemoryOnly = 1 << 2,
/**
* 此标志启用渐进式下载,图像在下载过程中逐步显示,就像浏览器一样。
* 默认情况下,图像只显示一次完全下载。
*/
SDWebImageProgressiveDownload = 1 << 3,
/**
* 刷新缓存
*/
SDWebImageRefreshCached = 1 << 4,
/**
* 后台加载
*/
SDWebImageContinueInBackground = 1 << 5,
/**
* 通过设置处理存储在NSHTTPCookieStorage中的cookie
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
*/
SDWebImageHandleCookies = 1 << 6,
/**
* 允许使用无效的SSL证书
*/
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
/**
* 优先下载
*/
SDWebImageHighPriority = 1 << 8,
/**
* 延迟占位符
*/
SDWebImageDelayPlaceholder = 1 << 9,
/**
* 改变动画形象
*/
SDWebImageTransformAnimatedImage = 1 << 10,
/**
* 默认情况下,下载后会将图像添加到imageView。 但在某些情况下,我们想要
*在设置图像之前握手(例如应用滤镜或添加交叉渐变动画)
*如果要在成功时手动设置完成图像,请使用此标志
*/
SDWebImageAvoidAutoSetImage = 1 << 11,
/**
* 默认情况下,图像会根据其原始大小进行解码。 在iOS上,此标志将缩小
*图像尺寸与设备的受限内存兼容。
*如果设置了“SDWebImageProgressiveDownload”标志,则停用缩小比例。
*/
SDWebImageScaleDownLargeImages = 1 << 12,
/**
* 默认情况下,当图像缓存在内存中时,我们不查询磁盘数据。 此掩码可以强制同时查询磁盘数据。
*建议将此标志与`SDWebImageQueryDiskSync`一起使用,以确保图像在同一个runloop中加载。
*/
SDWebImageQueryDataWhenInMemory = 1 << 13,
/**
* 默认情况下,我们同步查询内存缓存,异步查询磁盘缓存。 此掩码可以强制同步查询磁盘缓存,以确保在同一个runloop中加载映像。
*如果禁用内存缓存或在某些其他情况下,此标志可以避免在单元重用期间闪烁。
*/
SDWebImageQueryDiskSync = 1 << 14,
/**
* 默认情况下,当缓存丢失时,将从网络下载映像。 此标志可以阻止网络仅从缓存加载。
*/
SDWebImageFromCacheOnly = 1 << 15,
/**
* 默认情况下,当您使用`SDWebImageTransition`在图像加载完成后进行某些视图转换时,此转换仅适用于从网络下载图像。 此掩码也可以强制为内存和磁盘缓存应用视图转换。
*/
SDWebImageForceTransition = 1 << 16
==延伸==
“<<”是位运算中的左移运算符,第一个枚举值SDWebImageRetryFailed = 1 << 0,十进制1转化为二进制:0b00000001,这里<<0将所有二进制位左移0位,那么还是0b00000001,最终SDWebImageRetryFailed 值为1.
第二个枚举值SDWebImageLowPriority =1<<1,这里是将1的二进制所有位向左移动1位,空缺的用0补齐,那么0b00000001变成0b00000010,十进制为2则SDWebImageLowPriority值为2。
缓存时间
在SDImageCachaConfig.m文件里面,SDWebImage设置了一些默认值,其中就包括最大存储时间,一周:
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
判断图片类型
根据imageData的第一个字节,可以判断其图片类型。
第一个字节 | 图片类型 |
---|---|
0xFF | jpeg |
0x89 | png |
0x47 | gif |
0x4D\0x49 | tiff |
0x52 | 将imageData的前12个字节转化为字符串,如果是RIFF前缀和WEBP后缀,则图片类型是webp |
0x00 | 将imageData的前12个字节转化为字符串,如果是ftypheic 、ftypheix、ftyphevc 、ftyphevx后缀,则是HEIC或者HEIF类型 |
图片缓存清理
当系统发出内存不足通知时,会将内存中的所有图片缓存都删除掉;
当程序进入后台时,会对磁盘的文件数据进行清理;
当收到程序关闭通知时,会对磁盘中的文件数据进行清理。
SDWebImage 会在每次 APP 结束的时候执行清理任务。 清理缓存的规则分两步进行。 第一步先清除掉过期的缓存文件。 如果清除掉过期的缓存之后,空间还不够。 那么就继续按文件时间从早到晚排序,先清除最早的缓存文件,直到剩余空间达到要求。
具体点,SDWebImage 是怎么控制哪些缓存过期,以及剩余空间多少才够呢? 通过两个属性:
@interface SDImageCache : NSObject
@property (assign, nonatomic) NSInteger maxCacheAge;
@property (assign, nonatomic) NSUInteger maxCacheSize;
maxCacheAge 是文件缓存的时长, SDWebImage 会注册两个通知:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(cleanDisk)
name:UIApplicationWillTerminateNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundCleanDisk)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
分别在应用进入后台和结束的时候,遍历所有的缓存文件,如果缓存文件超过 maxCacheAge 中指定的时长,就会被删除掉。
同样的, maxCacheSize 控制 SDImageCache 所允许的最大缓存空间。 如果清理完过期文件后缓存空间依然没达到 maxCacheSize 的要求, 那么就会继续清理旧文件,直到缓存空间达到要求为止。
磁盘缓存清理步骤
1.获取磁盘中图片的最后修改日期。(为了减少磁盘和内存数据交换,读取是并不将整个文件读入内存,仅仅将文件的一些属性读入内存中,包括最后修改日期,该文件是否为文件夹,文件的大小和对应文件的文件路径)
2.根据最后修改日期将图片进行分类,将那些已经存放超过最长存放时间的文件存储在删除数组,其他的文件信息存储在另一个字典中。并计算除去要删除的文件之外的所有文件大小
3.根据删除数组中的文件路径,将对应的文件删除。
4.判断剩下的文件大小是否超过用户现在的磁盘最大容量。
5.如果超过,则将剩余的文件进行安修改时间进行升序排列,然后删除修改时间最早的文件,直到甚剩余文件大小小于最大磁盘容量的一半。
结语
至此就SDWebImage图片缓存机制和清除缓存做了一个简单的介绍,SDWebImage 是一个功能强大的开源库,而且一直保持着更新。功能请打但并不算很复杂,仔细研读一下它的代码,会发现内部很多机制设计的非常巧妙。篇幅有限,介绍就此结束,想要熟练的运用SDWebImage,还需要自己取研究源码,以及在实践中多多运用。
网友评论