源码阅读:SDWebImage(十二)——SDWebImageDownloaderOperation

646 阅读11分钟

该文章阅读的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(一)——从使用入手

源码阅读: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