SDWebImage初步学习以及缓存学习

SDWebImageUML图分析

SDWebImageUml图
  1. SDWebImageManager是管理的核心类,他聚合了SDWebImageManagerdelegate
  2. SDWebImagePrefetcher是预下载的,SDWebImageManager作为一个变量manager聚合在SDWebImagePrefetcher,并且聚合了变量为delegate的SDWebImagePrefetcherDelegate
  3. UIButton+WebCache、UIImageView+WebCache(图的左边)等category是依赖uiview+webCache,uiview+webCache又是依赖于SDWebImageManager
  4. SDImageCache和SDWebImageDownLoader作为属性聚合在manager中

SDWebImage时序图分析

这里写图片描述

核心类说明

这里写图片描述

SDWebImageManager

SDWebImageManager的SDWebImageOptions

我们在用SDWebImage都会用到SDWebImageOptions,下面说下他的含义

typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
    /**
     * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
     * 默认情况下,当一个 URL 下载失败,该URL被列入黑名单,将不会继续尝试下载

     * This flag disable this blacklisting.
     * 此标志取消黑名单

     */
    SDWebImageRetryFailed = 1 << 0, // 下载失败后还会重新去重试
    
    /**
     * By default, image downloads are started during UI interactions, this flags disable this feature,
     * 默认情况下,在 UI 交互时也会启动图像下载,此标记取消这一功能

     * leading to delayed download on UIScrollView deceleration for instance.
     * 会延迟下载,UIScrollView停止滚动之后再继续下载
     * 下载事件监听的运行循环模式是 NSDefaultRunLoopMode
     */
    SDWebImageLowPriority = 1 << 1,
    
    /**
     * This flag disables on-disk caching
     * 禁用磁盘缓存
     */
    SDWebImageCacheMemoryOnly = 1 << 2,

    /**
     * This flag enables progressive download, the image is displayed progressively during download as a browser would do.
     * 此标记允许渐进式下载,就像浏览器中那样,下载过程中,图像会逐步显示出来

     * By default, the image is only displayed once completely downloaded.
     * 默认情况下,图像只会在下载完后显示

     */
    SDWebImageProgressiveDownload = 1 << 3,

    /**
     * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
     * 即使图像被缓存,遵守 HTPP 响应的缓存控制,如果需要,从远程刷新图像

     * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
     * 磁盘缓存将由 NSURLCache 处理,而不是 SDWebImage,这会对性能有轻微的影响

     * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
     * 此选项有助于处理同一个请求 URL 的图像发生变化

     * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
     * 如果缓存的图像被刷新,会调用一次 completion block,并传递最终的图像

     *
     * Use this flag only if you can't make your URLs static with embedded cache busting parameter.
     * 仅在无法使用嵌入式缓存清理参数确定图像 URL 时,使用此标记

     */
    SDWebImageRefreshCached = 1 << 4,
    /**
     * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
     * 在 iOS 4+,当 App 进入后台后仍然会继续下载图像。这是向系统请求额外的后台时间以保证下载请求完成的

     * extra time in background to let the request finish. If the background task expires the operation will be cancelled.
     * 如果后台任务过期,请求将会被取消

     */
    SDWebImageContinueInBackground = 1 << 5, // 后台下载

    /**
     * Handles cookies stored in NSHTTPCookieStore by setting
     * 通过设置

     * NSMutableURLRequest.HTTPShouldHandleCookies = YES;
     * 处理保存在 NSHTTPCookieStore 中的 cookies

     */
    SDWebImageHandleCookies = 1 << 6, // 是否管理cookies
    /**
     * Enable to allow untrusted SSL certificates.
     * 允许不信任的 SSL 证书

     * Useful for testing purposes. Use with caution in production.
     * 可以出于测试目的使用,在正式产品中慎用

     */
    SDWebImageAllowInvalidSSLCertificates = 1 << 7,
    
    /**
     * By default, images are loaded in the order in which they were queued. This flag moves them to
     * 默认情况下,图像会按照在队列中的顺序被加载,此标记会将它们移动到队列前部立即被加载

     * the front of the queue.
     */
    SDWebImageHighPriority = 1 << 8,
    
    /**
     * By default, placeholder images are loaded while the image is loading. This flag will delay the loading
     * 默认情况下,在加载图像时,占位图像已经会被加载。而此标记会延迟加载占位图像,直到图像已经完成加载

     * of the placeholder image until after the image has finished loading.
     */
    SDWebImageDelayPlaceholder = 1 << 9, // 延迟占位图
    /**
     * We usually don't call transformDownloadedImage delegate method on animated images,
     * 通常不会在可动画的图像上调用 transformDownloadedImage 代理方法,因为大多数转换代码会破坏动画文件

     * as most transformation code would mangle it.
     * Use this flag to transform them anyway.
     * 使用此标记尝试转换
     */
    SDWebImageTransformAnimatedImage = 1 << 10, // 改变动画图像
    
    /**
     * By default, image is added to the imageView after download. But in some cases, we want to
     * have the hand before setting the image (apply a filter or add it with cross-fade animation for instance)
     * Use this flag if you want to manually set the image in the completion when success
     */
    SDWebImageAvoidAutoSetImage = 1 << 11  // 避免自动设置图像
};

SDImageCache

SDImageCache是sdWebImage的缓存处理

   _maxCacheAge = kDefaultCacheMaxCacheAge; // 7天

SDImageCache默认的最大缓存时间是7天

   // Init the memory cache 自动清除缓存
        _memCache = [[AutoPurgeCache alloc] init];
        _memCache.name = fullNamespace;


  // 清空内存
        [[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];

自动清除缓存

通过查看AutoPurgeCache可知,他是在发现UIApplicationDidReceiveMemoryWarningNotification即内存警告的时候,全部把缓存清除
另外程序终止的时候,清理磁盘。程序进入后台的时候,执行后台清理磁盘

清理缓存,就是把系统的缓存

- (void)clearMemory {
    [self.memCache removeAllObjects];
}

清理磁盘

清理磁盘的步骤

  1. 先清除已超过的最大缓存时间
  2. 第一轮会保留文件属性
  3. 清除之后,如果设置了最大的缓存, 保留之前的文件,先删除最老的文件
  4. 删除最老的文件, 到达它最大缓存的一半

- (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock {
    dispatch_async(self.ioQueue, ^{
        // 1.找到磁盘缓存目录
        NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES];
        
        // 2.创建了一个数组,放入了key
        /*
         NSURLIsDirectoryKey,  目录key
         NSURLContentModificationDateKey, 最后修改的时间key
         NSURLTotalFileAllocatedSizeKey 文件总大小的一个key
         */
        NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey];
       
        // 3.枚举器(迭代器的模式),类似于数组.
        // NSDirectoryEnumerationSkipsHiddenFiles 忽略隐藏文件
        NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL
                                                   includingPropertiesForKeys:resourceKeys
                                                                      options:NSDirectoryEnumerationSkipsHiddenFiles
                                                                 errorHandler:NULL];
        
        // 4. 从先现在开始,减去最大缓存时间
        NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge];
        
        // 5.定义字典
        NSMutableDictionary *cacheFiles = [NSMutableDictionary dictionary];
        // 6.定义当前缓存大小
        NSUInteger currentCacheSize = 0;

        // Enumerate all of the files in the cache directory.  This loop has two purposes:
        //
        //  1. Removing files that are older than the expiration date.
        //  2. Storing file attributes for the size-based cleanup pass.
        // 7.创建了一个可变数组
        NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init];
        
            // 8.使用for拿到了具体的URL
        /*
            1.清除了超过日期的文件
            2.以大小为基础的第二轮清除
         */
            for (NSURL *fileURL in fileEnumerator) {
                // 9. 访问单独的URL, 获取指定key的信息
            NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:NULL];

            // Skip directories.
                // 10. 判断是目录,就直接跳过
            if ([resourceValues[NSURLIsDirectoryKey] boolValue]) {
                continue;
            }

            // Remove files that are older than the expiration date;
                // 11. 拿到了文件的修改日期
            NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
            
                // 12.如果是最后的修改日期, 添加到数组
            if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) {
                [urlsToDelete addObject:fileURL];
                continue;
            }

            // Store a reference to this file and account for its total size.
                // 13.对没有过期的文件,用键值的方式添加到字典
            NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
            currentCacheSize += [totalAllocatedSize unsignedIntegerValue];
            [cacheFiles setObject:resourceValues forKey:fileURL];
        }
        
        // 14.删除过期的文件
        for (NSURL *fileURL in urlsToDelete) {
            [_fileManager removeItemAtURL:fileURL error:nil];
        }

        // If our remaining disk cache exceeds a configured maximum size, perform a second
        // size-based cleanup pass.  We delete the oldest files first.
        // 15. 设置了缓存上限,才会走if分支
        if (self.maxCacheSize > 0 && currentCacheSize > self.maxCacheSize) {
            // Target half of our maximum cache size for this cleanup pass.
            // 16. 所需要的缓存大小的一半
            const NSUInteger desiredCacheSize = self.maxCacheSize / 2;

            // Sort the remaining cache files by their last modification time (oldest first).
            // 17.最早进来的排前面
            NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent
                                                            usingComparator:^NSComparisonResult(id obj1, id obj2) {
                                                                return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]];
                                                            }];

            // Delete files until we fall below our desired cache size.
            // 18.删除文件,到低于缓存大小
            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;
                    }
                }
            }
        }
        if (completionBlock) {
            dispatch_async(dispatch_get_main_queue(), ^{
                completionBlock();
            });
        }
    });
}

PS NSCache

NSCache是系统提供的一种类似于集合(NSMutableDictionary)的缓存,它与集合的不同如下:

  1. NSCache具有自动删除的功能,以减少系统占用的内存;

  2. NSCache是线程安全的,不需要加线程锁;

  3. 键对象不会像 NSMutableDictionary 中那样被复制。(键不需要实现 NSCopying 协议)。

属性

@property NSUInteger totalCostLimit;

设置缓存占用的内存大小,并不是一个严格的限制,当总数超过了totalCostLimit设定的值,系统会清除一部分缓存,直至总消耗低于totalCostLimit的值。

@property NSUInteger countLimit;

设置缓存对象的大小,这也不是一个严格的限制。

- (id)objectForKey:(id)key;

获取缓存对象,基于key-value对

- (void)setObject:(id)obj forKey:(id)key; // 0 cost

存储缓存对象,考虑缓存的限制属性;

- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g;

存储缓存对象,cost是提前知道该缓存对象占用的字节数,也会考虑缓存的限制属性,建议直接使用 - (void)setObject:(id)obj forKey:(id)key;

NSCacheDelegate代理

代理属性声明如下:

@property (assign) iddelegate;

实现了NSCacheDelegate代理的对象,在缓存对象即将被清理的时候,系统回调代理方法如下:

-(void)cache:(NSCache *)cache willEvictObject:(id)obj;

第一个参数是当前缓存(NSCache),不要修改该对象;

第二个参数是当前将要被清理的对象,如果需要存储该对象,可以在此操作(存入Sqlite or CoreData);

该代理方法的调用会在缓存对象即将被清理的时候调用,如下场景会调用:

  1. -(void)removeObjectForKey:(id)key; 手动删除对象;

  2. 缓存对象超过了NSCache的属性限制;(countLimit 和 totalCostLimit )

  3. App进入后台会调用;

  4. 系统发出内存警告;

你可能感兴趣的:(SDWebImage初步学习以及缓存学习)