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;
}];