SDWebImage的简单剖析

1. 基本使用方式

1. sd_setImageWithURL:

//图片缓存的基本代码,就是这么简单
    [self.image1 sd_setImageWithURL:imagePath1];

2. sd_setImageWithURL:  completed:

//用block 可以在图片加载完成之后做些事情
    [self.image2 sd_setImageWithURL:imagePath2 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
         
        NSLog(@"这里可以在图片加载完成之后做些事情");
         
    }];
3. sd_setImageWithURL:  placeholderImage:
//给一张默认图片,先使用默认图片,当图片加载完成后再替换
    [self.image1 sd_setImageWithURL:imagePath1 placeholderImage:[UIImage imageNamed:@"default"]];
4. sd_setImageWithURL:  placeholderImage:  completed:

//使用默认图片,而且用block 在完成后做一些事情
    [self.image1 sd_setImageWithURL:imagePath1 placeholderImage:[UIImage imageNamed:@"default"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
         
        NSLog(@"图片加载完成后做的事情");
         
    }];
5. sd_setImageWithURL:  placeholderImage:  options:

//options 选择方式
     
    [self.image1 sd_setImageWithURL:imagePath1 placeholderImage:[UIImage imageNamed:@"default"] options:SDWebImageRetryFailed];


2.缓存策略-SDWebImageOptions

默认是开启了硬盘\内存缓存的
* SDWebImageRetryFailed   下载失败了会再次尝试下载

* SDWebImageLowPriority   当UIScrollView等正在滚动时,延迟下载图片(放置scrollView滚动卡)

* SDWebImageCacheMemoryOnly 只缓存到内存中,不缓存到硬盘上

* SDWebImageProgressiveDownload 图片会一点一点慢慢显示出来(就像浏览器显示网页上的图片一样)

* SDWebImageRefreshCached 将硬盘缓存交给系统自带的NSURLCache去处理,当同一个URL对应的图片经常更改时可以用这种策略

3. SDWebImageManger是最主要的管理类

* SDWebImageManger核心属性:
    * SDImageCache *imageCache;  // 负责管理缓存
    * SDWebImageDownloader *imageDownloader; // 管理下载器
    * NSMutableSet *failedURLs; / / 记录所有失败的URL名单
    * NSMutableArray *runningOperations; // 当前正在执行的操作

在外部有UIImageView+WebCache 和 UIButton+WebCache 为下载图片的操作提供接口
内部有SDWebImageManger负责处理和协调 SDWebImageDownloader 和 SDWebImageCache
SDWebImageDownloader负责具体的下载任务,SDWebImageCache负责关于缓存的工作:添加,删除,查询缓存。

4. SDWebImage 大概的流程可以分为 UIKit 层 和 工具层

UIKit层:
  • 框架最外层的类是UIImageView +WebCache,我们将图片的URL,占位图片直接给这个类。下面是这个类的公共接口
1. - (void)sd_setImageWithURL:(nullable NSURL *)url; 
2. - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder; 
3. - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options; 
4. - (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock; 
5. - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock;
6. - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock; 
7.  - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock;


// 以上这些方法最终走到  UIView+WebCache 中的  

- (void)sd_internalSetImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options operationKey:(nullable NSString *)operationKey setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock;
    方法

如果好奇为什么不是 UIImageView+WebCache而要上一层到UIView的分类里呢?
 因为SDWebImage框架也支持UIButton的下载图片等方法,所以需要在它们的父类:UIView里面统一一个下载方法。

工具层:
* SDWebImageManager同时管理SDImageCache和SDWebImageDownloader两个类,在下载任务开始的时候,SDWebImageManager首先访问SDImageCache来查询是否存在缓存,如果有缓存,直接返回缓存的图片。如果没有缓存,就命令SDWebImageDownloader来下载图片,下载成功后,存入缓存,显示图片。以上是SDWebImageManager大致的工作流程

* 下载方法只有一个 :
            * [SDWebImageManager.sharedManager loadImageWithURL:options:progress:completed:]
            *  loadImageWithURL 中 会有 [self.imageCache  queryCacheOperationForKey] 的操作 查询是否有缓存图片(SDImageCache 中是基于 NSCache 来实现的  通过key(url)来获取 缓存)
            * 如果不存在缓存 就开启下载器   在错误url名单中添加当前的url 到  failedURLs 中, 如果标记失败后可以重新下载 就把这个失败的url 在 failedURLs中移除  
                    * 下载成功就进行缓存 :  self.imageCache   调用   - (void)storeImage:(nullable UIImage *)image imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key  toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock 


* 一些关键操作的方法:
    *  SDImageCache.m  中. queryCacheOperationForKey. 查询缓存
            *  imageFromMemoryCacheForKey  查询内存缓存
            *  diskImageDataBySearchingAllPathsForKey  查询磁盘缓存 

SDWebImageDownloader

    * SDWebImageDownloader.m
            * NSOperationQueue *downloadQueue;//下载队列
            * NSOperation *lastAddedOperation;//最后添加的下载操作
            * Class operationClass;//操作类
            * NSMutableDictionary *URLOperations;//操作数组
            * SDHTTPHeadersMutableDictionary *HTTPHeaders;//HTTP请求头
            * dispatch_queue_t barrierQueue;//用来阻塞前面的下载线程(串行化)

    * 下载的核心方法 : - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options  progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock  completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock
    
    __weak SDWebImageDownloader *wself = self;

    return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^SDWebImageDownloaderOperation *{
        
        __strong __typeof (wself) sself = wself;
        
        NSTimeInterval timeoutInterval = sself.downloadTimeout;
        if (timeoutInterval == 0.0) {
            timeoutInterval = 15.0;
        }
        // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise
        
        //创建下载请求
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeoutInterval];
        request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
        request.HTTPShouldUsePipelining = YES;
        if (sself.headersFilter) {
            request.allHTTPHeaderFields = sself.headersFilter(url, [sself.HTTPHeaders copy]);
        }
        else {
            request.allHTTPHeaderFields = sself.HTTPHeaders;
        }
        
        //创建下载操作:SDWebImageDownloaderOperation用于请求网络资源的操作,它是一个 NSOperation 的子类
        SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options];
        operation.shouldDecompressImages = sself.shouldDecompressImages;
        
        //url证书
        if (sself.urlCredential) {
            operation.credential = sself.urlCredential;
        } else if (sself.username && sself.password) {
            operation.credential = [NSURLCredential credentialWithUser:sself.username password:sself.password persistence:NSURLCredentialPersistenceForSession];
        }
        
        //优先级
        if (options & SDWebImageDownloaderHighPriority) {
            operation.queuePriority = NSOperationQueuePriorityHigh;
        } else if (options & SDWebImageDownloaderLowPriority) {
            operation.queuePriority = NSOperationQueuePriorityLow;
        }

        //在下载队列里添加下载操作,执行下载操作
        [sself.downloadQueue addOperation:operation];
        
        //如果后进先出
        if (sself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
            // Emulate LIFO execution order by systematically adding new operations as last operation's dependency
            //addDependency:参数opertaion倍添加到NSOperationQueue后,只有等该opertion结束后才能执行其他的operation,实现了后进先出
            [sself.lastAddedOperation addDependency:operation];
            sself.lastAddedOperation = operation;
        }
        return operation;
    }];

SDWebImage的简单剖析_第1张图片
image.png

你可能感兴趣的:(SDWebImage的简单剖析)