该文章阅读的SDWebImage的版本为4.3.3。
这个类负责图像下载的相关操作
1.SDWebImageOperation协议
这个协议中只有一个方法,就是取消方法。即实现这个协议的类必须实现取消方法。
- (void)cancel;
2.全局静态常量
/**
下载任务开始的通知名
*/
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification;
/**
下载任务已经接收到响应的通知名
*/
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadReceiveResponseNotification;
/**
下载任务结束的通知名
*/
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification;
/**
下载任务完成的通知名
*/
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification;
3.SDWebImageDownloaderOperationInterface协议
这个协议定义了作为一个图片下载操作类必须要提供的功能。如果你想自己自定义一个图片下载操作类,需要继承NSOperation
类,并遵守这个协议。
/**
以指定请求对象、会话对象和下载选项初始化图片下载操作类
*/
- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request
inSession:(nullable NSURLSession *)session
options:(SDWebImageDownloaderOptions)options;
/**
添加进度回调block和完成回调block
*/
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
/**
是否解压缩图像对象
*/
- (BOOL)shouldDecompressImages;
/**
设置是否解压缩图像对象
*/
- (void)setShouldDecompressImages:(BOOL)value;
/**
认证挑战的证书
*/
- (nullable NSURLCredential *)credential;
/**
设置认证挑战的证书
*/
- (void)setCredential:(nullable NSURLCredential *)value;
/**
取消指定token的下载操作
*/
- (BOOL)cancel:(nullable id)token;
4.公共属性
/**
图像下载操作的请求对象
*/
@property (strong, nonatomic, readonly, nullable) NSURLRequest *request;
/**
图像下载操作的任务对象
*/
@property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask;
/**
是否解压缩图片
*/
@property (assign, nonatomic) BOOL shouldDecompressImages;
/**
该属性已经废弃
*/
@property (nonatomic, assign) BOOL shouldUseCredentialStorage __deprecated_msg("Property deprecated. Does nothing. Kept only for backwards compatibility");
/**
认证挑战的证书
*/
@property (nonatomic, strong, nullable) NSURLCredential *credential;
/**
下载选项
*/
@property (assign, nonatomic, readonly) SDWebImageDownloaderOptions options;
/**
预计大小
*/
@property (assign, nonatomic) NSInteger expectedSize;
/**
图像下载任务的响应对象
*/
@property (strong, nonatomic, nullable) NSURLResponse *response;
5.公共方法
/**
以指定请求对象、指定会话对象和下载操作对象
*/
- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request
inSession:(nullable NSURLSession *)session
options:(SDWebImageDownloaderOptions)options NS_DESIGNATED_INITIALIZER;
/**
添加监听进程block和监听完成block
*/
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
/**
取消指定token的图像下载操作
*/
- (BOOL)cancel:(nullable id)token;
6.私有宏
/**
利用GCD的信号量实现加锁的效果
*/
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
/**
利用GCD的信号量实现解锁的效果
*/
#define UNLOCK(lock) dispatch_semaphore_signal(lock);
7.私有静态常量
这三个静态常量在iOS8中是定义在CFNetwork.framework
中,这里再定义一遍是为了兼容iOS8而不引入CFNetwork.framework
#if (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
const float NSURLSessionTaskPriorityHigh = 0.75;
const float NSURLSessionTaskPriorityDefault = 0.5;
const float NSURLSessionTaskPriorityLow = 0.25;
#endif
定义回调block对应的key
static NSString *const kProgressCallbackKey = @"progress";
static NSString *const kCompletedCallbackKey = @"completed";
8.类型定义
定义了一个key是NSString
类型,value是id
类型的可变字典
typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
9.类扩展属性
/**
保存回调block
*/
@property (strong, nonatomic, nonnull) NSMutableArray<SDCallbacksDictionary *> *callbackBlocks;
/**
操作是否正在执行
*/
@property (assign, nonatomic, getter = isExecuting) BOOL executing;
/**
操作是否执行完成
*/
@property (assign, nonatomic, getter = isFinished) BOOL finished;
/**
保存图像数据
*/
@property (strong, nonatomic, nullable) NSMutableData *imageData;
/**
保存SDWebImageDownloaderIgnoreCachedResponse的缓存数据
*/
@property (copy, nonatomic, nullable) NSData *cachedData;
/**
一个弱引用的属性保存会话对象
*/
@property (weak, nonatomic, nullable) NSURLSession *unownedSession;
/**
一个强引用的属性保存会话对象
*/
@property (strong, nonatomic, nullable) NSURLSession *ownedSession;
/**
保存任务对象
*/
@property (strong, nonatomic, readwrite, nullable) NSURLSessionTask *dataTask;
/**
如果保证回调线程安全的锁
*/
@property (strong, nonatomic, nonnull) dispatch_semaphore_t callbacksLock; // a lock to keep the access to `callbackBlocks` thread-safe
/**
用于图像解码的队列
*/
@property (strong, nonatomic, nonnull) dispatch_queue_t coderQueue;
#if SD_UIKIT
/**
用于后台下载的任务ID
*/
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId;
#endif
/**
编解码器
*/
@property (strong, nonatomic, nullable) id<SDWebImageProgressiveCoder> progressiveCoder;
10.方法实现
10.1 私有方法
/**
获取指定密钥的回调block数组
*/
- (nullable NSArray<id> *)callbacksForKey:(NSString *)key {
// 加锁
LOCK(self.callbacksLock);
// 获取指定密钥下的回调block数组
NSMutableArray<id> *callbacks = [[self.callbackBlocks valueForKey:key] mutableCopy];
// 解锁
UNLOCK(self.callbacksLock);
// 移除数组中的[NSNull null]
[callbacks removeObjectIdenticalTo:[NSNull null]];
// 返回不可变数组
return [callbacks copy];
}
/**
取消
*/
- (void)cancelInternal {
// 如果当前状态是已完成就不继续向下执行了
if (self.isFinished) return;
// 调用父类的取消方法
[super cancel];
// 如果任务还在
if (self.dataTask) {
// 取消任务
[self.dataTask cancel];
// 主队列异步回调发送通知
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:weakSelf];
});
// 改变记录状态的属性
if (self.isExecuting) self.executing = NO;
if (!self.isFinished) self.finished = YES;
}
// 调用重启方法
[self reset];
}
/**
完成
*/
- (void)done {
// 改变记录状态的属性
self.finished = YES;
self.executing = NO;
// 调用重启方法
[self reset];
}
/**
重启
*/
- (void)reset {
// 加锁
LOCK(self.callbacksLock);
// 移除所有保存的回调block
[self.callbackBlocks removeAllObjects];
// 解锁
UNLOCK(self.callbacksLock);
// 任务对象置空
self.dataTask = nil;
// 会话对象取消并置空
if (self.ownedSession) {
[self.ownedSession invalidateAndCancel];
self.ownedSession = nil;
}
}
/**
根据后缀缩放图片
*/
- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image {
return SDScaledImageForKey(key, image);
}
/**
应用进入后台后是不继续下载任务
*/
- (BOOL)shouldContinueWhenAppEntersBackground {
return self.options & SDWebImageDownloaderContinueInBackground;
}
/**
下载出错的情况下回调完成block
*/
- (void)callCompletionBlocksWithError:(nullable NSError *)error {
[self callCompletionBlocksWithImage:nil imageData:nil error:error finished:YES];
}
/**
下载成功的情况下回调完成block
*/
- (void)callCompletionBlocksWithImage:(nullable UIImage *)image
imageData:(nullable NSData *)imageData
error:(nullable NSError *)error
finished:(BOOL)finished {
NSArray<id> *completionBlocks = [self callbacksForKey:kCompletedCallbackKey];
dispatch_main_async_safe(^{
for (SDWebImageDownloaderCompletedBlock completedBlock in completionBlocks) {
completedBlock(image, imageData, error, finished);
}
});
}
10.2 SDWebImageDownloaderOperationInterface协议方法
- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request
inSession:(nullable NSURLSession *)session
options:(SDWebImageDownloaderOptions)options {
// 调用父类的初始化方法
if ((self = [super init])) {
// 保存请求对象
_request = [request copy];
// 默认是解压缩图像
_shouldDecompressImages = YES;
// 保存下载选项
_options = options;
// 初始化可变数组保存回调block
_callbackBlocks = [NSMutableArray new];
// 执行状态设置为NO
_executing = NO;
// 完成状态状态设置为NO
_finished = NO;
// 预计大小默认为0
_expectedSize = 0;
// 用弱引用的属性保存会话对象
_unownedSession = session;
// 生成信号量
_callbacksLock = dispatch_semaphore_create(1);
// 生成串行队列
_coderQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderOperationCoderQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock {
// 创建可变字典保存进度回调block和完成回调block
SDCallbacksDictionary *callbacks = [NSMutableDictionary new];
if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy];
if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy];
// 加锁
LOCK(self.callbacksLock);
// 用数组保存可变字典
[self.callbackBlocks addObject:callbacks];
// 解锁
UNLOCK(self.callbacksLock);
// 返回可变字典
return callbacks;
}
- (BOOL)cancel:(nullable id)token {
// 创建变量保存是否需要取消,默认为NO
BOOL shouldCancel = NO;
// 加锁
LOCK(self.callbacksLock);
// 移除token对应的回调block
[self.callbackBlocks removeObjectIdenticalTo:token];
// 如果没有回调block就设置为YES
if (self.callbackBlocks.count == 0) {
shouldCancel = YES;
}
// 解锁
UNLOCK(self.callbacksLock);
// 如果需要取消就取消
if (shouldCancel) {
[self cancel];
}
// 返回是否需要取消
return shouldCancel;
}
10.3 重写父类NSOperation方法
- (nonnull instancetype)init {
// 调用自定义初始化方法
return [self initWithRequest:nil inSession:nil options:0];
}
- (void)start {
// 同步锁
@synchronized (self) {
// 如果当前状态是取消
if (self.isCancelled) {
// 完成状态设置为YES
self.finished = YES;
// 调用重置
[self reset];
// 返回
return;
}
#if SD_UIKIT
// 如果设置了后台下载选项,就申请后台任务
Class UIApplicationClass = NSClassFromString(@"UIApplication");
BOOL hasApplication = UIApplicationClass && [UIApplicationClass respondsToSelector:@selector(sharedApplication)];
if (hasApplication && [self shouldContinueWhenAppEntersBackground]) {
__weak __typeof__ (self) wself = self;
UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)];
self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{
__strong __typeof (wself) sself = wself;
if (sself) {
// 取消任务
[sself cancel];
[app endBackgroundTask:sself.backgroundTaskId];
sself.backgroundTaskId = UIBackgroundTaskInvalid;
}
}];
}
#endif
// 获取会话对象
NSURLSession *session = self.unownedSession;
// 如果没获取到会话对象
if (!session) {
// 创建一个会话对象并设置请求超时时间为15秒
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForRequest = 15;
session = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:nil];
self.ownedSession = session;
}
// 如果设置了忽略NSURLCache
if (self.options & SDWebImageDownloaderIgnoreCachedResponse) {
// 从绘画对象中获取缓存数据
NSURLCache *URLCache = session.configuration.URLCache;
// 如果没有就获取单例
if (!URLCache) {
URLCache = [NSURLCache sharedURLCache];
}
// 获取缓存响应对象
NSCachedURLResponse *cachedResponse;
@synchronized (URLCache) {
cachedResponse = [URLCache cachedResponseForRequest:self.request];
}
// 获取缓存数据
if (cachedResponse) {
self.cachedData = cachedResponse.data;
}
}
// 创建图像下载任务
self.dataTask = [session dataTaskWithRequest:self.request];
// 执行状态设置为YES
self.executing = YES;
}
if (self.dataTask) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
// 设置下载任务的优先级
if ([self.dataTask respondsToSelector:@selector(setPriority:)]) {
if (self.options & SDWebImageDownloaderHighPriority) {
self.dataTask.priority = NSURLSessionTaskPriorityHigh;
} else if (self.options & SDWebImageDownloaderLowPriority) {
self.dataTask.priority = NSURLSessionTaskPriorityLow;
}
}
#pragma clang diagnostic pop
// 启动下载任务
[self.dataTask resume];
// 回调进度block
for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) {
progressBlock(0, NSURLResponseUnknownLength, self.request.URL);
}
// 主队列异步发送通知
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:weakSelf];
});
} else {
// 如果下载任务创建失败就回调错误
[self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUnknown userInfo:@{NSLocalizedDescriptionKey : @"Task can't be initialized"}]];
// 结束
[self done];
return;
}
#if SD_UIKIT
// 如果开启了后台下载任务就结束任务
Class UIApplicationClass = NSClassFromString(@"UIApplication");
if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) {
return;
}
if (self.backgroundTaskId != UIBackgroundTaskInvalid) {
UIApplication * app = [UIApplication performSelector:@selector(sharedApplication)];
[app endBackgroundTask:self.backgroundTaskId];
self.backgroundTaskId = UIBackgroundTaskInvalid;
}
#endif
}
- (void)cancel {
// 调用自定义的取消方法
@synchronized (self) {
[self cancelInternal];
}
}
- (void)setFinished:(BOOL)finished {
// 手动实现KVO发送
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
}
- (void)setExecuting:(BOOL)executing {
// 手动实现KVO发送
[self willChangeValueForKey:@"isExecuting"];
_executing = executing;
[self didChangeValueForKey:@"isExecuting"];
}
- (BOOL)isConcurrent {
// 始终返回YES
return YES;
}
10.3 NSURLSessionDataDelegate代理方法
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
// 创建变量保存会话响应意向,默认为允许
NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
// 创建变量保存预期大小,默认为0
NSInteger expected = (NSInteger)response.expectedContentLength;
expected = expected > 0 ? expected : 0;
// 属性保存预期大小
self.expectedSize = expected;
// 属性保存响应对象
self.response = response;
// 获取响应状态码
NSInteger statusCode = [response respondsToSelector:@selector(statusCode)] ? ((NSHTTPURLResponse *)response).statusCode : 200;
// 创建变量保存是否有效:状态码比400小就有效
BOOL valid = statusCode < 400;
// 但是如果状态码是304并且没有缓存数据,就设置为无效
if (statusCode == 304 && !self.cachedData) {
valid = NO;
}
if (valid) {
// 如果有效,回调进度block
for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) {
progressBlock(0, expected, self.request.URL);
}
} else {
// 如果无效设置会话响应意向为取消
disposition = NSURLSessionResponseCancel;
}
// 发送通知
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadReceiveResponseNotification object:weakSelf];
});
// 返回会话响应意向
if (completionHandler) {
completionHandler(disposition);
}
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
// 初始化属性保存图像数据
if (!self.imageData) {
self.imageData = [[NSMutableData alloc] initWithCapacity:self.expectedSize];
}
// 保存下载的数据
[self.imageData appendData:data];
// 如果设置渐进式下载并且预期大小大于零
if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) {
// 获取已经下载的图像数据
__block NSData *imageData = [self.imageData copy];
// 获取已经下载的图像大小
const NSInteger totalSize = imageData.length;
// 如果已下载的图像大小不小于预期大小就是下载完成
BOOL finished = (totalSize >= self.expectedSize);
// 创建逐行编解码器
if (!self.progressiveCoder) {
for (id<SDWebImageCoder>coder in [SDWebImageCodersManager sharedInstance].coders) {
if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] &&
[((id<SDWebImageProgressiveCoder>)coder) canIncrementallyDecodeFromData:imageData]) {
self.progressiveCoder = [[[coder class] alloc] init];
break;
}
}
}
// 串行队列异步执行
dispatch_async(self.coderQueue, ^{
// 逐行解码图像数据获取图像对象
UIImage *image = [self.progressiveCoder incrementallyDecodedImageWithData:imageData finished:finished];
if (image) {
// 根据图像的地址获取缓存密钥
NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL];
// 缩放图像
image = [self scaledImageForKey:key image:image];
// 如果需要解压缩就解压缩
if (self.shouldDecompressImages) {
image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}];
}
// 回调完成block
[self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO];
}
});
}
// 回调进度block
for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) {
progressBlock(self.imageData.length, self.expectedSize, self.request.URL);
}
}
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler {
NSCachedURLResponse *cachedResponse = proposedResponse;
// 如果没设置使用NSURLCache就将缓存响应置空后返回
if (!(self.options & SDWebImageDownloaderUseNSURLCache)) {
cachedResponse = nil;
}
if (completionHandler) {
completionHandler(cachedResponse);
}
}
10.4 NSURLSessionTaskDelegate代理方法
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
// 同步锁
@synchronized(self) {
// 保存下载任务的属性置空
self.dataTask = nil;
// 发送通知
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:weakSelf];
if (!error) {
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadFinishNotification object:weakSelf];
}
});
}
if (error) {
// 如果出错就回调错误
[self callCompletionBlocksWithError:error];
// 完成
[self done];
} else {
// 如果有完成回调的block
if ([self callbacksForKey:kCompletedCallbackKey].count > 0) {
// 获取到下载的图像数据
__block NSData *imageData = [self.imageData copy];
if (imageData) {
// 如果设置了忽略缓存响应选项,并且缓存数据和下载数据相同
if (self.options & SDWebImageDownloaderIgnoreCachedResponse && [self.cachedData isEqualToData:imageData]) {
// 完成回调返回空
[self callCompletionBlocksWithImage:nil imageData:nil error:nil finished:YES];
// 完成
[self done];
} else {
// 串行队列异步执行
dispatch_async(self.coderQueue, ^{
// 解码图像数据获得图像对象
UIImage *image = [[SDWebImageCodersManager sharedInstance] decodedImageWithData:imageData];
// 根据图像地址获取图像缓存密钥
NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL];
// 缩放图像对象
image = [self scaledImageForKey:key image:image];
// 如果图像是GIF和WebP格式的就不解码
BOOL shouldDecode = YES;
if (image.images) {
shouldDecode = NO;
} else {
#ifdef SD_WEBP
SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:imageData];
if (imageFormat == SDImageFormatWebP) {
shouldDecode = NO;
}
#endif
}
// 如果需要解码,并且需要解压缩就进行解压缩
if (shouldDecode) {
if (self.shouldDecompressImages) {
BOOL shouldScaleDown = self.options & SDWebImageDownloaderScaleDownLargeImages;
image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(shouldScaleDown)}];
}
}
// 获取图像大小
CGSize imageSize = image.size;
if (imageSize.width == 0 || imageSize.height == 0) {
// 如果图像没有大小就回调错误
[self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]];
} else {
// 如果图像有大小就回调结果
[self callCompletionBlocksWithImage:image imageData:imageData error:nil finished:YES];
}
// 完成
[self done];
});
}
} else {
// 如果没有图像数据就回调错误
[self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]];
// 完成
[self done];
}
} else {
// 没有完成回调block就调用完成方法
[self done];
}
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
// 创建变量保存验证挑战意向
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
// 创建变量保存证书
__block NSURLCredential *credential = nil;
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
// 如果证书验证方法是信任服务器
if (!(self.options & SDWebImageDownloaderAllowInvalidSSLCertificates)) {
// 如果设置了信任无效SSL证书意向就设置为默认
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
} else {
// 如果没设置,生成证书,意向是通过证书
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
disposition = NSURLSessionAuthChallengeUseCredential;
}
} else {
if (challenge.previousFailureCount == 0) {
// 如果失败尝试数为0
if (self.credential) {
// 如果有证书就设置意向为通过证书
credential = self.credential;
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
// 如果没有证书就设置意向为取消
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
} else {
// 如果失败尝试数不为0,就设置意向为取消
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
}
// 返回意向和证书
if (completionHandler) {
completionHandler(disposition, credential);
}
}
11.总结
这个类主要是对图像下载操作的处理。利用传入的请求对象和会话对象创建下载任务,在下载任务代理方法中处理下载过程中的种种情况,通过传入的回调block反馈下载进度和下载结果。
源码阅读系列:SDWebImage
源码阅读:SDWebImage(二)——SDWebImageCompat
源码阅读:SDWebImage(三)——NSData+ImageContentType
源码阅读:SDWebImage(四)——SDWebImageCoder
源码阅读:SDWebImage(五)——SDWebImageFrame
源码阅读:SDWebImage(六)——SDWebImageCoderHelper
源码阅读:SDWebImage(七)——SDWebImageImageIOCoder
源码阅读:SDWebImage(八)——SDWebImageGIFCoder
源码阅读:SDWebImage(九)——SDWebImageCodersManager
源码阅读:SDWebImage(十)——SDImageCacheConfig
源码阅读:SDWebImage(十一)——SDImageCache
源码阅读:SDWebImage(十二)——SDWebImageDownloaderOperation
源码阅读:SDWebImage(十三)——SDWebImageDownloader
源码阅读:SDWebImage(十四)——SDWebImageManager
源码阅读:SDWebImage(十五)——SDWebImagePrefetcher
源码阅读:SDWebImage(十六)——SDWebImageTransition
源码阅读:SDWebImage(十七)——UIView+WebCacheOperation
源码阅读:SDWebImage(十八)——UIView+WebCache
源码阅读:SDWebImage(十九)——UIImage+ForceDecode/UIImage+GIF/UIImage+MultiFormat
源码阅读:SDWebImage(二十)——UIButton+WebCache
源码阅读:SDWebImage(二十一)——UIImageView+WebCache/UIImageView+HighlightedWebCache