源码阅读:SDWebImage(十三)——SDWebImageDownloader

961 阅读10分钟

该文章阅读的SDWebImage的版本为4.3.3。

这个类是下载器类,管理着图像的下载。

1.公共枚举

/**
 这个位枚举定义了下载器的可选项
 */
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
    /**
     低优先级
     */
    SDWebImageDownloaderLowPriority = 1 << 0,
    
    /**
     渐进式下载
     */
    SDWebImageDownloaderProgressiveDownload = 1 << 1,

    /**
     默认情况下,请求阻止使用NSURLCache。设置这个选项就会使用NSURLCache
     */
    SDWebImageDownloaderUseNSURLCache = 1 << 2,

    /**
     这个选项要与上面那个选项配合使用,如果图像是从NSURLCache读取的,
     那么回调block中返回的image和imageData参数就是nil
     */
    SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
    
    /**
     应用进入后台时继续下载
     */
    SDWebImageDownloaderContinueInBackground = 1 << 4,

    /**
     通过设置NSMutableURLRequest.HTTPShouldHandleCookies = YES获取保存在NSHTTPCookieStore中的cookies
     */
    SDWebImageDownloaderHandleCookies = 1 << 5,

    /**
     允许接受不受信任的SSL证书
     */
    SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6,

    /**
     高优先级
     */
    SDWebImageDownloaderHighPriority = 1 << 7,
    
    /**
     缩小图片
     */
    SDWebImageDownloaderScaleDownLargeImages = 1 << 8,
};
/**
 这个枚举定义了下载执行顺序
 */
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
    /**
     先进先出,默认情况
     */
    SDWebImageDownloaderFIFOExecutionOrder,

    /**
     后进先出
     */
    SDWebImageDownloaderLIFOExecutionOrder
};

2.公共常量

/**
 下载开始通知名称
 */
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification;
/**
 下载停止通知名称
 */
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification;

3.公共类型定义

/**
 下载进度回调block
 */
typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL);
/**
 下载完成回调block
 */
typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished);
/**
 HTTP请求头字典
 */
typedef NSDictionary<NSString *, NSString *> SDHTTPHeadersDictionary;
/**
 HTTP请求头可变字典
 */
typedef NSMutableDictionary<NSString *, NSString *> SDHTTPHeadersMutableDictionary;
/**
 HTTP请求头过滤算法block
 */
typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterBlock)(NSURL * _Nullable url, SDHTTPHeadersDictionary * _Nullable headers);

4.SDWebImageDownloadToken类

4.1 公共属性

/**
 用于下载的url
 */
@property (nonatomic, strong, nullable) NSURL *url;
/**
 用于取消的token
 */
@property (nonatomic, strong, nullable) id downloadOperationCancelToken;

4.2 类扩展属性

/**
 下载操作对象
 */
@property (nonatomic, weak, nullable) NSOperation<SDWebImageDownloaderOperationInterface> *downloadOperation;

4.3 实现

- (void)cancel {
    // 有下载操作对象
    if (self.downloadOperation) {
        // 有取消token
        SDWebImageDownloadToken *cancelToken = self.downloadOperationCancelToken;
        if (cancelToken) {
            // 取消下载操作
            [self.downloadOperation cancel:cancelToken];
        }
    }
}

5.公共属性

/**
 解压图像可以提高性能,但会占用大量内存。
 默认为YES。如果由于过多的内存消耗而遇到崩溃,请将此项设置为NO。
 */
@property (assign, nonatomic) BOOL shouldDecompressImages;
/**
 最大并发下载数量
 */
@property (assign, nonatomic) NSInteger maxConcurrentDownloads;
/**
 仍需要下载的载量
 */
@property (readonly, nonatomic) NSUInteger currentDownloadCount;
/**
 下载请求超时的时间,默认15秒
 */
@property (assign, nonatomic) NSTimeInterval downloadTimeout;
/**
 会话配置对象
 */
@property (readonly, nonatomic, nonnull) NSURLSessionConfiguration *sessionConfiguration;
/**
 下载顺序
 */
@property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder;
/**
 请求操作的证书
 */
@property (strong, nonatomic, nullable) NSURLCredential *urlCredential;
/**
 证书的用户名
 */
@property (strong, nonatomic, nullable) NSString *username;
/**
 证书的密码
 */
@property (strong, nonatomic, nullable) NSString *password;
/**
 为HTTP请求头设置过滤器
 */
@property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter;

6.公共方法

/**
 获取单例对象
 */
+ (nonnull instancetype)sharedDownloader;
/**
 以指定会话配置对象初始化
 */
- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration NS_DESIGNATED_INITIALIZER;
/**
 为HTTP请求头添加字段
 */
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field;
/**
 获取HTTP请求头指定字段的值
 */
- (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field;
/**
 设置下载操作对象
 */
- (void)setOperationClass:(nullable Class)operationClass;
/**
 下载指定url的图像
 */
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
                                                   options:(SDWebImageDownloaderOptions)options
                                                  progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                                 completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
/**
 取消指定token的操作
 */
- (void)cancel:(nullable SDWebImageDownloadToken *)token;
/**
 设置下载的暂停状态
 */
- (void)setSuspended:(BOOL)suspended;
/**
 取消所有的下载
 */
- (void)cancelAllDownloads;
/**
 以指定会话配置对象创建新的会话对象
 */
- (void)createNewSessionWithConfiguration:(nonnull NSURLSessionConfiguration *)sessionConfiguration;
/**
 使会话对象无效并取消任务
 */
- (void)invalidateSessionAndCancel:(BOOL)cancelPendingOperations;

7.私有宏

/**
 利用GCD的信号量实现加锁的效果
 */
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
/**
 利用GCD的信号量实现解锁的效果
 */
#define UNLOCK(lock) dispatch_semaphore_signal(lock);

8.类扩展属性

/**
 下载操作队列
 */
@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;
/**
 最后添加的操作对象
 */
@property (weak, nonatomic, nullable) NSOperation *lastAddedOperation;
/**
 下载操作类
 */
@property (assign, nonatomic, nullable) Class operationClass;
/**
 保存url和其对应的操作对象
 */
@property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, SDWebImageDownloaderOperation *> *URLOperations;
/**
 HTTP请求头
 */
@property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders;
/**
 用于保证对属性URLOperations操作线程安全的锁
 */
@property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock;
/**
 用于保证对属性HTTPHeaders操作线程安全的锁
 */
@property (strong, nonatomic, nonnull) dispatch_semaphore_t headersLock;
/**
 会话对象
 */
@property (strong, nonatomic) NSURLSession *session;

9.实现

9.1 生命周期方法

+ (void)initialize {
    // 如果获取到了SDNetworkActivityIndicator类
    if (NSClassFromString(@"SDNetworkActivityIndicator")) {

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        // 获取SDNetworkActivityIndicator类的单例对象
        id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")];
#pragma clang diagnostic pop

        // 移除之前添加的观察者
        [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStartNotification object:nil];
        [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStopNotification object:nil];

        // 添加观察者
        [[NSNotificationCenter defaultCenter] addObserver:activityIndicator
                                                 selector:NSSelectorFromString(@"startActivity")
                                                     name:SDWebImageDownloadStartNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:activityIndicator
                                                 selector:NSSelectorFromString(@"stopActivity")
                                                     name:SDWebImageDownloadStopNotification object:nil];
    }
}
- (nonnull instancetype)init {
    // 以默认会话配置对象初始化
    return [self initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
}
- (void)dealloc {
    // 取消任务并使会话对象无效
    [self.session invalidateAndCancel];
    // 保存会话对象的属性置空
    self.session = nil;

    // 取消操作队列中所有操作
    [self.downloadQueue cancelAllOperations];
}

9.2 私有方法

/**
 添加下载操作
 */
- (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock
                                           completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock
                                                   forURL:(nullable NSURL *)url
                                           createCallback:(SDWebImageDownloaderOperation *(^)(void))createCallback {
    // url是必传的
    if (url == nil) {
        if (completedBlock != nil) {
            completedBlock(nil, nil, nil, NO);
        }
        return nil;
    }
    
    // 加锁
    LOCK(self.operationsLock);
    // 从缓存中获取url对应的操作对象
    SDWebImageDownloaderOperation *operation = [self.URLOperations objectForKey:url];
    // 如果没获取到,防止同一图像重复下载
    if (!operation) {
        // 从参数中获取操作对象
        operation = createCallback();
        __weak typeof(self) wself = self;
        operation.completionBlock = ^{
            // 操作完成时,从缓存中移除该url对应的操作对象
            __strong typeof(wself) sself = wself;
            if (!sself) {
                return;
            }
            LOCK(sself.operationsLock);
            [sself.URLOperations removeObjectForKey:url];
            UNLOCK(sself.operationsLock);
        };
        // 缓存url和其对应的操作对象
        [self.URLOperations setObject:operation forKey:url];
        // 将操作对象添加到操作队列中
        [self.downloadQueue addOperation:operation];
    }
    // 解锁
    UNLOCK(self.operationsLock);

    // 生成下载操作取消token
    id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock];
    
    // 生成下载token
    SDWebImageDownloadToken *token = [SDWebImageDownloadToken new];
    token.downloadOperation = operation;
    token.url = url;
    token.downloadOperationCancelToken = downloadOperationCancelToken;

    // 返回token
    return token;
}
/**
 获取操作队列中task对应的下载操作对象
 */
- (SDWebImageDownloaderOperation *)operationWithTask:(NSURLSessionTask *)task {
    // 创建变量奥村下载操作对象
    SDWebImageDownloaderOperation *returnOperation = nil;
    // 遍历找到task对应的下载操作对象
    for (SDWebImageDownloaderOperation *operation in self.downloadQueue.operations) {
        if (operation.dataTask.taskIdentifier == task.taskIdentifier) {
            returnOperation = operation;
            break;
        }
    }
    // 返回下载操作对象
    return returnOperation;
}

9.3 公共方法

+ (nonnull instancetype)sharedDownloader {
    // 获取该类的单例对象
    static dispatch_once_t once;
    static id instance;
    dispatch_once(&once, ^{
        instance = [self new];
    });
    return instance;
}
- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration {
    if ((self = [super init])) {
        // 操作对象类默认是SDWebImageDownloaderOperation
        _operationClass = [SDWebImageDownloaderOperation class];
        // 默认是解压缩图像
        _shouldDecompressImages = YES;
        // 默认顺序是先进先出
        _executionOrder = SDWebImageDownloaderFIFOExecutionOrder;
        // 初始化操作队列对象
        _downloadQueue = [NSOperationQueue new];
        // 默认最大并发下载数为6
        _downloadQueue.maxConcurrentOperationCount = 6;
        // 设置操作队列对象的名称
        _downloadQueue.name = @"com.hackemist.SDWebImageDownloader";
        // 初始化字典
        _URLOperations = [NSMutableDictionary new];
#ifdef SD_WEBP
        // 如果有webp格式的图像的HTTP请求头
        _HTTPHeaders = [@{@"Accept": @"image/webp,image/*;q=0.8"} mutableCopy];
#else
        // 如果没有webp格式的图像的HTTP请求头
        _HTTPHeaders = [@{@"Accept": @"image/*;q=0.8"} mutableCopy];
#endif
        // 利用GCD的信号量初始化锁
        _operationsLock = dispatch_semaphore_create(1);
        // 利用GCD的信号量初始化锁
        _headersLock = dispatch_semaphore_create(1);
        // 默认15秒下载请求超时
        _downloadTimeout = 15.0;

        // 创建会话对象
        [self createNewSessionWithConfiguration:sessionConfiguration];
    }
    return self;
}
- (void)createNewSessionWithConfiguration:(NSURLSessionConfiguration *)sessionConfiguration {
    // 取消所有下载
    [self cancelAllDownloads];

    // 如果当前有会话就对象就取消会话对象的任务并使会话对象无效
    if (self.session) {
        [self.session invalidateAndCancel];
    }

    // 设置会话配置对象的请求超时时间
    sessionConfiguration.timeoutIntervalForRequest = self.downloadTimeout;

    // 创建会话对象
    self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                 delegate:self
                                            delegateQueue:nil];
}
- (void)invalidateSessionAndCancel:(BOOL)cancelPendingOperations {
    // 当前类是SDWebImageDownloader的单例对象就不继续向下执行
    if (self == [SDWebImageDownloader sharedDownloader]) {
        return;
    }
    if (cancelPendingOperations) {
        // 取消任务并使会话对象无效
        [self.session invalidateAndCancel];
    } else {
        // 等待任务完成并使会话对象无效
        [self.session finishTasksAndInvalidate];
    }
}
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field {
    // 加锁
    LOCK(self.headersLock);
    if (value) {
        // 如果传入了值,就给指定字段赋值
        self.HTTPHeaders[field] = value;
    } else {
        // 如果未传值,就删除指定字段
        [self.HTTPHeaders removeObjectForKey:field];
    }
    // 解锁
    UNLOCK(self.headersLock);
}
- (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field {
    // 获取HTTP头中指定字段的值
    if (!field) {
        return nil;
    }
    return [[self allHTTPHeaderFields] objectForKey:field];
}
- (void)setOperationClass:(nullable Class)operationClass {
    // 操作对象类必须是NSOperation类的子类,并且遵守了SDWebImageDownloaderOperationInterface协议,否则就设置为SDWebImageDownloaderOperation类
    if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperationInterface)]) {
        _operationClass = operationClass;
    } else {
        _operationClass = [SDWebImageDownloaderOperation class];
    }
}
- (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;
        // 获取下载请求超时时间,默认15秒
        NSTimeInterval timeoutInterval = sself.downloadTimeout;
        if (timeoutInterval == 0.0) {
            timeoutInterval = 15.0;
        }

        // 根据设置的选项不同,设置不同的请求缓存策略
        NSURLRequestCachePolicy cachePolicy = options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData;
        // 创建请求对象
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url
                                                                    cachePolicy:cachePolicy
                                                                timeoutInterval:timeoutInterval];
                                                                
        // Cookies处理方式
        request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
        // 默认使用管线化
        request.HTTPShouldUsePipelining = YES;
        // 设置HTTP请求头字段
        if (sself.headersFilter) {
            request.allHTTPHeaderFields = sself.headersFilter(url, [sself allHTTPHeaderFields]);
        }
        else {
            request.allHTTPHeaderFields = [sself allHTTPHeaderFields];
        }
        // 创建下载操作对象
        SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options];
        // 设置下载操作对象是否解压缩
        operation.shouldDecompressImages = sself.shouldDecompressImages;
        
        // 设置下载操作对象的证书
        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;
        }
        
        // 如果设置了后进先出就通过添加依赖的方式实现
        if (sself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
            [sself.lastAddedOperation addDependency:operation];
            sself.lastAddedOperation = operation;
        }

        // 将生成的操作对象作为参数传递
        return operation;
    }];
}
- (void)cancel:(nullable SDWebImageDownloadToken *)token {
    // 获取token中的url,如果没有就不继续执行了
    NSURL *url = token.url;
    if (!url) {
        return;
    }
    // 加锁
    LOCK(self.operationsLock);
    // 获取到url对应的操作对象
    SDWebImageDownloaderOperation *operation = [self.URLOperations objectForKey:url];
    // 取消操作
    if (operation) {
        BOOL canceled = [operation cancel:token.downloadOperationCancelToken];
        // 移除url对应的操作对象
        if (canceled) {
            [self.URLOperations removeObjectForKey:url];
        }
    }
    // 解锁
    UNLOCK(self.operationsLock);
}
- (void)setSuspended:(BOOL)suspended {
    // 设置暂停状态
    self.downloadQueue.suspended = suspended;
}
- (void)cancelAllDownloads {
    // 取消所有操作
    [self.downloadQueue cancelAllOperations];
}

9.4 自定义getting/setting

- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads {
    // 直接给下载操作队列对象的最大并发数赋值
    _downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads;
}

- (NSInteger)maxConcurrentDownloads {
    // 返回下载操作队列对象的最大并发数
    return _downloadQueue.maxConcurrentOperationCount;
}
- (NSUInteger)currentDownloadCount {
    // 返回当前下载操作队列中操作对象数量
    return _downloadQueue.operationCount;
}
- (NSURLSessionConfiguration *)sessionConfiguration {
    // 返回会话对象配置对象
    return self.session.configuration;
}

9.5 NSURLSessionDataDelegate方法实现

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {

    // 如果调用这个代理方法的dataTask是SDWebImageDownloaderOperation生成的,就将代理方法实现转交给SDWebImageDownloaderOperation类对象去实现
    SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask];
    if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:didReceiveResponse:completionHandler:)]) {
        [dataOperation URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler];
    } else {
        // 如果不是的话就默认响应意向为允许
        if (completionHandler) {
            completionHandler(NSURLSessionResponseAllow);
        }
    }
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {

    // 如果调用这个代理方法的dataTask是SDWebImageDownloaderOperation生成的,就将代理方法实现转交给SDWebImageDownloaderOperation类对象去实现
    SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask];
    if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:didReceiveData:)]) {
        [dataOperation URLSession:session dataTask:dataTask didReceiveData:data];
    }
}
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
 willCacheResponse:(NSCachedURLResponse *)proposedResponse
 completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler {

    // 如果调用这个代理方法的dataTask是SDWebImageDownloaderOperation生成的,就将代理方法实现转交给SDWebImageDownloaderOperation类对象去实现
    SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask];
    if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:willCacheResponse:completionHandler:)]) {
        [dataOperation URLSession:session dataTask:dataTask willCacheResponse:proposedResponse completionHandler:completionHandler];
    } else {
        if (completionHandler) {
            completionHandler(proposedResponse);
        }
    }
}

9.6 NSURLSessionTaskDelegate方法实现

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    
    // 如果调用这个代理方法的dataTask是SDWebImageDownloaderOperation生成的,就将代理方法实现转交给SDWebImageDownloaderOperation类对象去实现
    SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task];
    if ([dataOperation respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]) {
        [dataOperation URLSession:session task:task didCompleteWithError:error];
    }
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
    
    // 如果调用这个代理方法的dataTask是SDWebImageDownloaderOperation生成的,就将代理方法实现转交给SDWebImageDownloaderOperation类对象去实现
    SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task];
    if ([dataOperation respondsToSelector:@selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)]) {
        [dataOperation URLSession:session task:task willPerformHTTPRedirection:response newRequest:request completionHandler:completionHandler];
    } else {
        if (completionHandler) {
            completionHandler(request);
        }
    }
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {

    // 如果调用这个代理方法的dataTask是SDWebImageDownloaderOperation生成的,就将代理方法实现转交给SDWebImageDownloaderOperation类对象去实现
    SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task];
    if ([dataOperation respondsToSelector:@selector(URLSession:task:didReceiveChallenge:completionHandler:)]) {
        [dataOperation URLSession:session task:task didReceiveChallenge:challenge completionHandler:completionHandler];
    } else {
        if (completionHandler) {
            completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
        }
    }
}

10.总结

这个类从字面上理解是一个下载器类,实际看代码,发现这个类并没有做实际的下载,而是维护着一个NSURLSession对象和一个NSOperationQueue对象,管理着一些SDWebImageDownloaderOperation对象。

SDWebImageDownloader通过传入的参数生成一个SDWebImageDownloaderOperation对象,并添加到操作队列中。具体的网络下载操作则由SDWebImageDownloaderOperation对象自己处理。

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