美文网首页
解读SDWebImage

解读SDWebImage

作者: 劳模007_Mars | 来源:发表于2018-11-30 17:33 被阅读0次
    SDWebImage_logo.png

    SDWebImage是一个功能强大的图片缓存框架,可以实现网络图片加载和缓存。那么SDWebImage的缓存机制是如何实现的呢?缓存时间是多久?清除缓存的策略是怎样的?让我们带着这些问题,走进源码,解读SDWebImage。

    SDWebImage提供一个UIImageView的分类 UIImageView+WebCache,用来加载和缓存来通关HTTP传输的图片资源。提供了缓存管理、异步下载、缓存校验等功能。

    缓存机制

    SDWebImage 的图片缓存采用的是 MemoryDisk 双重Cache机制,也就是二级缓存。SDWebImage的缓存机制可以简单概括为:第一次请求加载图片后将图片缓存在内存中,并通过md5加密将图片的url进行加密处理,加密处理后的值作为key,将图片存储在磁盘中。当再次加载图片时,先在内存缓存中寻找,如果内存中找不到图片,则在默认的磁盘中寻找,如果还是找不到,则再请求加载图片

    SDWebImage流程.png

    核心类:

    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,还需要自己取研究源码,以及在实践中多多运用。

    相关文章

      网友评论

          本文标题:解读SDWebImage

          本文链接:https://www.haomeiwen.com/subject/twohcqtx.html