这篇学习 SDWebImageDownloader 这个类。

  首先依然是看 SDWebImageDownloader.h:

  SDWebImageDownloaderOptions

 1 typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
 2     SDWebImageDownloaderLowPriority = 1 << 0,
 3     SDWebImageDownloaderProgressiveDownload = 1 << 1,
 4
 5     /**
 6      * By default, request prevent the use of NSURLCache. With this flag, NSURLCache
 7      * is used with default policies.
 8      */
 9     SDWebImageDownloaderUseNSURLCache = 1 << 2,
10
11     /**
12      * Call completion block with nil image/imageData if the image was read from NSURLCache
13      * (to be combined with `SDWebImageDownloaderUseNSURLCache`).
14      */
15
16     SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
17     /**
18      * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
19      * extra time in background to let the request finish. If the background task expires the operation will be cancelled.
20      */
21
22     SDWebImageDownloaderContinueInBackground = 1 << 4,
23
24     /**
25      * Handles cookies stored in NSHTTPCookieStore by setting
26      * NSMutableURLRequest.HTTPShouldHandleCookies = YES;
27      */
28     SDWebImageDownloaderHandleCookies = 1 << 5,
29
30     /**
31      * Enable to allow untrusted SSL certificates.
32      * Useful for testing purposes. Use with caution in production.
33      */
34     SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6,
35
36     /**
37      * Put the image in the high priority queue.
38      */
39     SDWebImageDownloaderHighPriority = 1 << 7,
40
41     /**
42      * Scale down the image
43      */
44     SDWebImageDownloaderScaleDownLargeImages = 1 << 8,
45 };

  这是一个 NS_OPTIONS 的枚举,用来表示不同的下载选项。

  当需要给某个功能添加 Options 的时候或者对不同的情况分类的时候,一般使用枚举来实现。

  提供的了 9 种不同的情况,且他们都是可以根据不同的需求进行匹配选择。这里的给每一个选项赋值使用了掩码,"<< " 表示左移操作,>> 表示右移操作。1<<0  表示把 1 转化为二进制然后整体左移 0 位,没有变化当然还是 1。1 << 1 则是把 1 转化为二进制是 0b0000 0001,把它整体左移 1 位是 0b0000 0010 它转化为 10 进制是 2,即左移一位表示在原来的值上乘以 2 。所以上面表示的枚举值自上而下分别是 1 左移 0 位至 8 位,表示的 NSUInteger 分别是: 0b0000 0001、0b0000 0010、0b0000 0100、0b0000 1000、0b0001 0000、0b0010 0000、0b0100 0000、0b1000 000 ...

  所以在判断 self.option 是否是某个枚举值的时候,直接拿 self.option 与要判断的枚举值做 与 操作:

1 self.option & SDWebImageDownloaderIgnoreCacheResponse

  SDWebImageDownloaderExecutionOrder

 1 typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
 2     /**
 3      * Default value. All download operations will execute in queue style (first-in-first-out).
 4      */
 5     SDWebImageDownloaderFIFOExecutionOrder,
 6
 7     /**
 8      * All download operations will execute in stack style (last-in-first-out).
 9      */
10     SDWebImageDownloaderLIFOExecutionOrder
11 };

  这是一个 NS_ENUM 的枚举,用来表示下载时数据被调用的顺序。

  FIFO (first-in-first-out 先进先出)、LIFO (last-in-first-out 后进先出),下载图像一般按照放入队列中的顺序依次进行,不过这里同时也支持后放入队列任务的先下载的操作。

  一个下载管理器应该这样管理下载,肯定有一个下载列表,可以假定这个列表保存在一个数组中,正常情况下应该每次取出数组中第1个元素来下载,这就是 FIFO (先进先出)。那么要改为 LIFO (后进先出),应该是针对某一个下载的,不应该是把取出数据的顺序改为从数组的最后一个元素取出。

  SDWebImageDownloadStartNotification、

SDWebImageDownloadStopNotification

1 extern NSString * _Nonnull const SDWebImageDownloadStartNotification;
2 extern NSString * _Nonnull const SDWebImageDownloadStopNotification;

  它们两个的赋值在 SDWebImageDownloaderOpertion.m 里面:

1 NSString *const SDWebImageDownloadStartNotification = @"SDWebImageDownloadStartNotification";
2 NSString *const SDWebImageDownloadStopNotification = @"SDWebImageDownloadStopNotification";

  

  SDWebImageDownloaderProgressBlock、

SDWebImageDownloaderCompletedBlock

1 typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL);
2
3 typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished);

  命名两个 block ,一个是下载进度的 block,一个下载完成的 block。

  SDHTTPHeadersDictionary、

SDHTTPHeadersMutableDictionary

1 typedef NSDictionary<NSString *, NSString *> SDHTTPHeadersDictionary;
2 typedef NSMutableDictionary<NSString *, NSString *> SDHTTPHeadersMutableDictionary;

  命名两个 key 和 value 都是字符串,用于 SDHTTPHeaders 的字典。

  SDWebImageDownloaderHeadersFilterBlock

1 typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterBlock)(NSURL * _Nullable url, SDHTTPHeadersDictionary * _Nullable headers);

  这个 block 用来自定义请求头。

  SDWebImageDownloadToken

1 @interface SDWebImageDownloadToken : NSObject
2
3 @property (nonatomic, strong, nullable) NSURL *url;
4 @property (nonatomic, strong, nullable) id downloadOperationCancelToken;
5
6 @end

  这个类表示与每一个下载相关的 token,能用于取消一个下载。

  SDWebImageDownloadToken 作为每一个下载的唯一身份标识。SDWebImageDownloader 和我们平时开发中的下载还是有不一样的地方的,它弱化了下载过程,比较强调的是下载结果。不支持断点下载(当然这可能没有必要)。

  如果需要设计一个自己的下载管理者,就应该设计一个类似 SDWebImageDownloadToken 这样的下载对象封装类,需要的所有信息,都能在这个对象中获取。

  

  SDWebImageDownloader

1 /**
2  * Asynchronous downloader dedicated and optimized for image loading.
3  */
4 @interface SDWebImageDownloader : NSObject

  异步下载专用的图像加载优化。

  shouldDecompressImages

1 /**
2  * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory.
3  * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
4  */
5 @property (assign, nonatomic) BOOL shouldDecompressImages;

   是否解压图像,解压下载和缓存的图像可以提高性能,但是会消耗大量的内存,默认是 YES,如果因消耗内存过大可以设置为 NO。

  maxConcurrentDownloads

1 /**
2  *  The maximum number of concurrent downloads
3  */
4 @property (assign, nonatomic) NSInteger maxConcurrentDownloads;

  表示并发下载的最大数量。

  currentDownloadCount

1 /**
2  * Shows the current amount of downloads that still need to be downloaded
3  */
4 @property (readonly, nonatomic) NSUInteger currentDownloadCount;

  显示当前仍需要下载的下载量。

  downloadTimeout

1 /**
2  *  The timeout value (in seconds) for the download operation. Default: 15.0.
3  */
4 @property (assign, nonatomic) NSTimeInterval downloadTimeout;

  下载操作的超时时间,单位是秒。默认是 15 秒。

  executionOrder

1 /**
2  * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`.
3  */
4 @property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder;

  更改下载操作的执行顺序。默认是 FIFO。

  sharedDownloader

1 /**
2  *  Singleton method, returns the shared instance
3  *
4  *  @return global shared instance of downloader class
5  */
6 + (nonnull instancetype)sharedDownloader;

  单例方法。

  urlCredential

1 /**
2  *  Set the default URL credential to be set for request operations.
3  */
4 @property (strong, nonatomic, nullable) NSURLCredential *urlCredential;

  设置默认的 URL 凭据,以设置请求操作。

  username、password

1 /**
2  * Set username
3  */
4 @property (strong, nonatomic, nullable) NSString *username;
5
6 /**
7  * Set password
8  */
9 @property (strong, nonatomic, nullable) NSString *password;

  headersFilter

1 /**
2  * Set filter to pick headers for downloading image HTTP request.
3  *
4  * This block will be invoked for each downloading image request, returned
5  * NSDictionary will be used as headers in corresponding HTTP request.
6  */
7 @property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter;

  设置筛选器以选择用于下载图像 http 请求的标头。该 block 将被调用为每个下载图像请求,返回一个 NSDictionary 作为相应的 http 请求头。

  

  Method

1 /**
2  * Creates an instance of a downloader with specified session configuration.
3  * *Note*: `timeoutIntervalForRequest` is going to be overwritten.
4  * @return new instance of downloader class
5  */
6 - (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration NS_DESIGNATED_INITIALIZER;

  使用一个 NSURLSessionConfiguration 实例做参数,创建一个具有指定的 NSURLSessionConfiguration  的下载实例。

  使用 NS_DESIGNATED_INITIALIZER 表示指定的初始化方法。

1 /**
2  * Set a value for a HTTP header to be appended to each download HTTP request.
3  *
4  * @param value The value for the header field. Use `nil` value to remove the header.
5  * @param field The name of the header field to set.
6  */
7 - (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field;

  设置附加到每个下载 HTTP 请求的 HTTP 头的值。

1 /**
2  * Returns the value of the specified HTTP header field.
3  *
4  * @return The value associated with the header field field, or `nil` if there is no corresponding header field.
5  */
6 - (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field;

  返回指定的 HTTP 头字段的的值。

1 /**
2  * Sets a subclass of `SDWebImageDownloaderOperation` as the default
3  * `NSOperation` to be used each time SDWebImage constructs a request
4  * operation to download an image.
5  *
6  * @param operationClass The subclass of `SDWebImageDownloaderOperation` to set
7  *        as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`.
8  */
9 - (void)setOperationClass:(nullable Class)operationClass;

 1 /**
 2  * Creates a SDWebImageDownloader async downloader instance with a given URL
 3  *
 4  * The delegate will be informed when the image is finish downloaded or an error has happen.
 5  *
 6  * @see SDWebImageDownloaderDelegate
 7  *
 8  * @param url            The URL to the image to download
 9  * @param options        The options to be used for this download
10  * @param progressBlock  A block called repeatedly while the image is downloading
11  *                       @note the progress block is executed on a background queue
12  * @param completedBlock A block called once the download is completed.
13  *                       If the download succeeded, the image parameter is set, in case of error,
14  *                       error parameter is set with the error. The last parameter is always YES
15  *                       if SDWebImageDownloaderProgressiveDownload isn't use. With the
16  *                       SDWebImageDownloaderProgressiveDownload option, this block is called
17  *                       repeatedly with the partial image object and the finished argument set to NO
18  *                       before to be called a last time with the full image and finished argument
19  *                       set to YES. In case of error, the finished argument is always YES.
20  *
21  * @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation
22  */
23 - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
24                                                    options:(SDWebImageDownloaderOptions)options
25                                                   progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
26                                                  completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;

  使用指定的 URL 创建一个 SDWebImageDownloader 异步下载实例。

  当图像下载完成和下载错误时,将通知代理。

1 /**
2  * Cancels a download that was previously queued using -downloadImageWithURL:options:progress:completed:
3  *
4  * @param token The token received from -downloadImageWithURL:options:progress:completed: that should be canceled.
5  */
6 - (void)cancel:(nullable SDWebImageDownloadToken *)token;

  取消先前排队使用的下载。

1 /**
2  * Sets the download queue suspension state
3  */
4 - (void)setSuspended:(BOOL)suspended;

  设置下载队列挂起状态。

1 /**
2  * Cancels all download operations in the queue
3  */
4 - (void)cancelAllDownloads;

  取消队列中的所有下载操作。

  SDWebImageDownloader.m

  

 1 @implementation SDWebImageDownloadToken
 2 @end
 3
 4
 5 @interface SDWebImageDownloader () <NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
 6
 7 @property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;
 8 @property (weak, nonatomic, nullable) NSOperation *lastAddedOperation;
 9 @property (assign, nonatomic, nullable) Class operationClass;
10 @property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, SDWebImageDownloaderOperation *> *URLOperations;
11 @property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders;
12 // This queue is used to serialize the handling of the network responses of all the download operation in a single queue
13 @property (SDDispatchQueueSetterSementics, nonatomic, nullable) dispatch_queue_t barrierQueue;
14
15 // The session in which data tasks will run
16 @property (strong, nonatomic) NSURLSession *session;
17
18 @end

  NSOperationQueue *downloadQueue 下载的队列。

  NSOperation *lastAddedOperation 用于纪录最后添加的操作。

  Class operationClass  支持自定义的操作类。

  NSMutableDictionary<NSURL *, SDWebImageDownloaderOperation *> URLOperations 存放着所有的 operation。

  SDHTTPHeadersMutableDictionary *HTTPHeaders HTTP 请求头。

  dispatch_queue_t barrierQueue 这个队列是用于序列化所有下载操作的网络响应的处理在一个单一的队列。

  NSURLSession *session 数据任务将运行的的会话。

  initialize

 1 + (void)initialize {
 2     // Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator )
 3     // To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import
 4     if (NSClassFromString(@"SDNetworkActivityIndicator")) {
 5
 6 #pragma clang diagnostic push
 7 #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
 8         id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")];
 9 #pragma clang diagnostic pop
10
11         // Remove observer in case it was previously added.
12         [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStartNotification object:nil];
13         [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStopNotification object:nil];
14
15         [[NSNotificationCenter defaultCenter] addObserver:activityIndicator
16                                                  selector:NSSelectorFromString(@"startActivity")
17                                                      name:SDWebImageDownloadStartNotification object:nil];
18         [[NSNotificationCenter defaultCenter] addObserver:activityIndicator
19                                                  selector:NSSelectorFromString(@"stopActivity")
20                                                      name:SDWebImageDownloadStopNotification object:nil];
21     }
22 }

  initialize 和 load 这两个方法:

  执行时机: load 在程序运行后立即执行 initialize 在类的方法第一次被调用时执行

  若自身未定义,是否沿用父类的方法:load 否 initialize 是

  类别中的定义: load 全部执行,但后于类中的方法,initialize 覆盖类中的方法,只执行一个

  上面 initialize 里面的方法实现,是为了在图片下载的时候绑定一个 SDNetworkActivityIndicator,当引入 SDNetworkActivityIndicator 类的时候,先获得 SDNetworkActivityIndicator 的单例类,然后首先移除之前添加的 SDWebImageDownloadStartNotification、SDWebImageDownloadStopNotification 的通知,然后重新添加 Start 和 Stop 通知,当 Start 的时候执行 startActivity 方法,当 Stop 的时候执行 stopActivity 方法。

  sharedDownloader

1 + (nonnull instancetype)sharedDownloader {
2     static dispatch_once_t once;
3     static id instance;
4     dispatch_once(&once, ^{
5         instance = [self new];
6     });
7     return instance;
8 }

  单例方法实现。

  init

 1 - (nonnull instancetype)init {
 2     return [self initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
 3 }
 4
 5 - (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration {
 6     if ((self = [super init])) {
 7         _operationClass = [SDWebImageDownloaderOperation class];
 8         _shouldDecompressImages = YES;
 9         _executionOrder = SDWebImageDownloaderFIFOExecutionOrder;
10         _downloadQueue = [NSOperationQueue new];
11         _downloadQueue.maxConcurrentOperationCount = 6;
12         _downloadQueue.name = @"com.hackemist.SDWebImageDownloader";
13         _URLOperations = [NSMutableDictionary new];
14 #ifdef SD_WEBP
15         _HTTPHeaders = [@{@"Accept": @"image/webp,image/*;q=0.8"} mutableCopy];
16 #else
17         _HTTPHeaders = [@{@"Accept": @"image/*;q=0.8"} mutableCopy];
18 #endif
19         _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT);
20         _downloadTimeout = 15.0;
21
22         sessionConfiguration.timeoutIntervalForRequest = _downloadTimeout;
23
24         /**
25          *  Create the session for this task
26          *  We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate
27          *  method calls and completion handler calls.
28          */
29         self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
30                                                      delegate:self
31                                                 delegateQueue:nil];
32     }
33     return self;
34 }

  自定义初始化方法实现。对上面提到的属性默认赋值。SDWebImageDownloaderOperation 为自定义类、默认解压、下载顺序 FIFO、并发下载是 6、15 秒超时等等。

  _HTTPHeaders 比较特殊:  

  "image/webp,image/*;q=0.8" 是什么意思? image/webp 是 web 格式的图片,q=0.8 指的是权重系数为0.8,q 的取值范围是 0 - 1, 默认值为 1,q 作用于它前边分号(;)前边的内容。在这里,image/webp,image/*;q=0.8 表示优先接受 image/webp,其次接受 image/* 的图片。

  dealloc

1 - (void)dealloc {
2     [self.session invalidateAndCancel];
3     self.session = nil;
4
5     [self.downloadQueue cancelAllOperations];
6     SDDispatchQueueRelease(_barrierQueue);
7 }

  .h 里面的一堆 SET 和 GET 方法实现

 1 - (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field {
 2     if (value) {
 3         self.HTTPHeaders[field] = value;
 4     }
 5     else {
 6         [self.HTTPHeaders removeObjectForKey:field];
 7     }
 8 }
 9
10 - (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field {
11     return self.HTTPHeaders[field];
12 }
13
14 - (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads {
15     _downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads;
16 }
17
18 - (NSUInteger)currentDownloadCount {
19     return _downloadQueue.operationCount;
20 }
21
22 - (NSInteger)maxConcurrentDownloads {
23     return _downloadQueue.maxConcurrentOperationCount;
24 }
25
26 - (void)setOperationClass:(nullable Class)operationClass {
27     if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperationInterface)]) {
28         _operationClass = operationClass;
29     } else {
30         _operationClass = [SDWebImageDownloaderOperation class];
31     }
32 }

  token

 1 - (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock
 2                                            completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock
 3                                                    forURL:(nullable NSURL *)url
 4                                            createCallback:(SDWebImageDownloaderOperation *(^)())createCallback {
 5     // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data.
 6     if (url == nil) {
 7         if (completedBlock != nil) {
 8             completedBlock(nil, nil, nil, NO);
 9         }
10         return nil;
11     }
12
13     __block SDWebImageDownloadToken *token = nil;
14
15     dispatch_barrier_sync(self.barrierQueue, ^{
16         SDWebImageDownloaderOperation *operation = self.URLOperations[url];
17         if (!operation) {
18             operation = createCallback();
19             self.URLOperations[url] = operation;
20
21             __weak SDWebImageDownloaderOperation *woperation = operation;
22             operation.completionBlock = ^{
23               SDWebImageDownloaderOperation *soperation = woperation;
24               if (!soperation) return;
25               if (self.URLOperations[url] == soperation) {
26                   [self.URLOperations removeObjectForKey:url];
27               };
28             };
29         }
30         id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock];
31
32         token = [SDWebImageDownloadToken new];
33         token.url = url;
34         token.downloadOperationCancelToken = downloadOperationCancelToken;
35     });
36
37     return token;
38 }

  每一个图片的 URL 都会被作为对应的下载操作的唯一标识,每一个下载都会绑定一个 progressBlock 和一个 completeBlock,最后还用这个 URL 与 SDWebImageDownloaderOperation 建立联系。

  该 URL 将被作为回调字典的关键所以不能为 nil。如果是 nil 则直接调用没有数据和 image 的完成的 block。

  定义一个 __block 修饰的 SDWebImageDownloadToken 实例 token。

  在 self.barrierQueue 队列中使用 dispatch_barrier_sync 同步执行:

  使用 URL 从 self.URLOperations 中获取指定的 SDWebImageDownloaderOperation。

  如果 operation 不存在:

  operation = createCallback(); 执行这个 block。

  把 operation 存入 self.URLOperations 字典里面。

  operation 的  completionBlock 的实现,从 self.URLOperations 里面删除 URL 对应的 SDWebImageDownloaderOperation。

  把完成的 block 和 进度的 block 添加进 operation 的 _callbackBlocks 里面。

  downloadOperationCancelToken 是一个存放了完成 block 和进度 block 的字典。

  给 token 赋值。

  返回 token。

  创建 SDWebImageDownloaderOperation 

 1 - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
 2                                                    options:(SDWebImageDownloaderOptions)options
 3                                                   progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
 4                                                  completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock {
 5     __weak SDWebImageDownloader *wself = self;
 6
 7     return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^SDWebImageDownloaderOperation *{
 8         __strong __typeof (wself) sself = wself;
 9         NSTimeInterval timeoutInterval = sself.downloadTimeout;
10         if (timeoutInterval == 0.0) {
11             timeoutInterval = 15.0;
12         }
13
14         // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise
15         NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeoutInterval];
16         request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
17         request.HTTPShouldUsePipelining = YES;
18         if (sself.headersFilter) {
19             request.allHTTPHeaderFields = sself.headersFilter(url, [sself.HTTPHeaders copy]);
20         }
21         else {
22             request.allHTTPHeaderFields = sself.HTTPHeaders;
23         }
24         SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options];
25         operation.shouldDecompressImages = sself.shouldDecompressImages;
26
27         if (sself.urlCredential) {
28             operation.credential = sself.urlCredential;
29         } else if (sself.username && sself.password) {
30             operation.credential = [NSURLCredential credentialWithUser:sself.username password:sself.password persistence:NSURLCredentialPersistenceForSession];
31         }
32
33         if (options & SDWebImageDownloaderHighPriority) {
34             operation.queuePriority = NSOperationQueuePriorityHigh;
35         } else if (options & SDWebImageDownloaderLowPriority) {
36             operation.queuePriority = NSOperationQueuePriorityLow;
37         }
38
39         [sself.downloadQueue addOperation:operation];
40         if (sself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
41             // Emulate LIFO execution order by systematically adding new operations as last operation's dependency
42             [sself.lastAddedOperation addDependency:operation];
43             sself.lastAddedOperation = operation;
44         }
45
46         return operation;
47     }];
48 }

  用 __weak 修饰  self。

  调用上面的返回 Token 的方法:

  主要看 createCallback 的实现:

  在 block 内部使用 __strong 修饰 self。

  设置超时时间。

  创建 request,主要注意缓存策略的选择。

  给  request 的  HTTPShouldHandleCookies 和 HTTPShouldUsePipelining 赋值。

  设置请求头。

  创建 SDWebImageDownloaderOperation。

  给 SDWebImageDownloaderOperation 设置 urlCredential。

  给 SDWebImageDownloaderOperation 设置操作的优先级。

  把操作添加进队列里面。

  根据 _executionOrder 是先进先出还是先进后出,给操作添加依赖。

  取消某个操作

1 - (void)cancel:(nullable SDWebImageDownloadToken *)token {
2     dispatch_barrier_async(self.barrierQueue, ^{
3         SDWebImageDownloaderOperation *operation = self.URLOperations[token.url];
4         BOOL canceled = [operation cancel:token.downloadOperationCancelToken];
5         if (canceled) {
6             [self.URLOperations removeObjectForKey:token.url];
7         }
8     });
9 }

  

  设置队列挂起

1 - (void)setSuspended:(BOOL)suspended {
2     (self.downloadQueue).suspended = suspended;
3 }

  

  全部操作取消

1 - (void)cancelAllDownloads {
2     [self.downloadQueue cancelAllOperations];
3 }

  

  Helper methods

 1 #pragma mark Helper methods
 2
 3 - (SDWebImageDownloaderOperation *)operationWithTask:(NSURLSessionTask *)task {
 4     SDWebImageDownloaderOperation *returnOperation = nil;
 5     for (SDWebImageDownloaderOperation *operation in self.downloadQueue.operations) {
 6         if (operation.dataTask.taskIdentifier == task.taskIdentifier) {
 7             returnOperation = operation;
 8             break;
 9         }
10     }
11     return returnOperation;
12 }

    

  NSURLSessionDataDelegate

  self.session 在初始化的时候把 delegate 设置为了当前类,且 SDWebImageDownloader 遵守 NSURLSessionTaskDelegateNSURLSessionDataDelegate 协议,当使用 self.session 请求数据,收到响应的的时候,会调用 SDWebImageDownloader.m 里面实现的代理方法,然后在调用 SDWebImageDownloaderOperation 里面的代理方法。第一次见这样的设计,作者的目的是为了共用一个 URLSession。

 1 - (void)URLSession:(NSURLSession *)session
 2           dataTask:(NSURLSessionDataTask *)dataTask
 3 didReceiveResponse:(NSURLResponse *)response
 4  completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
 5
 6     // Identify the operation that runs this task and pass it the delegate method
 7     SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask];
 8
 9     [dataOperation URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler];
10 }
11
12 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
13
14     // Identify the operation that runs this task and pass it the delegate method
15     SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask];
16
17     [dataOperation URLSession:session dataTask:dataTask didReceiveData:data];
18 }
19
20 - (void)URLSession:(NSURLSession *)session
21           dataTask:(NSURLSessionDataTask *)dataTask
22  willCacheResponse:(NSCachedURLResponse *)proposedResponse
23  completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler {
24
25     // Identify the operation that runs this task and pass it the delegate method
26     SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask];
27
28     [dataOperation URLSession:session dataTask:dataTask willCacheResponse:proposedResponse completionHandler:completionHandler];
29 }

  

  NSURLSessionDataDelegate

 1 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
 2     // Identify the operation that runs this task and pass it the delegate method
 3     SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task];
 4
 5     [dataOperation URLSession:session task:task didCompleteWithError:error];
 6 }
 7
 8 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
 9
10     completionHandler(request);
11 }
12
13 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
14
15     // Identify the operation that runs this task and pass it the delegate method
16     SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task];
17
18     [dataOperation URLSession:session task:task didReceiveChallenge:challenge completionHandler:completionHandler];
19 }

参考链接:http://www.jianshu.com/p/8411e4645f0d

END

转载于:https://www.cnblogs.com/chmhml/p/6956727.html

SDWebImage源码阅读(九)SDWebImageDownloader相关推荐

  1. SDWebImage源码阅读(三)UIImage+GIF

    UIImage+GIF 是UIImage 类的一个GIF 分类,在之前的版本里面这个分类是用了处理GIF 动态图片的但是会有内存暴增的bug.在当前 '4.0.0-beta2' 的版本里GIF 动态图 ...

  2. 源码阅读:SDWebImage(十九)——UIImage+ForceDecode/UIImage+GIF/UIImage+MultiFormat

    该文章阅读的SDWebImage的版本为4.3.3. 由于这几个分类都是UIImage的分类,并且内容相对较少,就写在一篇文章中. 1.UIImage+ForceDecode 这个分类为UIImage ...

  3. 源码阅读:SDWebImage(六)——SDWebImageCoderHelper

    该文章阅读的SDWebImage的版本为4.3.3. 这个类提供了四个方法,这四个方法可分为两类,一类是动图处理,一类是图像方向处理. 1.私有函数 先来看一下这个类里的两个函数 /**这个函数是计算 ...

  4. 源码阅读:SDWebImage(五)——SDWebImageFrame

    该文章阅读的SDWebImage的版本为4.3.3. 根据SDWebImage作者的描述,这个类是用来帮助创建动图的. 1.接口文件 属性 /**当前帧的图像*/ @property (nonatom ...

  5. 源码阅读:SDWebImage(二十)——UIButton+WebCache

    该文章阅读的SDWebImage的版本为4.3.3. 这个分类提供了为UIButton设置网络图像的快捷方法. 1.公共方法 1.1.设置image的方法 /**获取当前图像链接地址*/ - (nul ...

  6. 源码阅读:SDWebImage(二十一)——UIImageView+WebCache/UIImageView+HighlightedWebCache

    该文章阅读的SDWebImage的版本为4.3.3. 这两个分类都是UIImageView的分类,功能也都是设置图片,所以就写在一起. 1.UIImageView+WebCache 1.1.公共方法 ...

  7. 源码阅读:SDWebImage(十)——SDImageCacheConfig

    该文章阅读的SDWebImage的版本为4.3.3. 这个类是图片缓存的配置类,保存图片缓存的配置或选项. 1.属性 /**是否解压默认是YES,解压可以提高性能,但会占用大量内存:如果由于内存消耗过 ...

  8. Soul网关源码阅读(九)插件配置加载初探

    Soul网关源码阅读(九)插件配置加载初探 简介     今日来探索一下插件的初始化,及相关的配置的加载 源码Debug 插件初始化     首先来到我们非常熟悉的插件链调用的类: SoulWebHa ...

  9. Go-Excelize API源码阅读(十九)——SetHeaderFooter

    Go-Excelize API源码阅读(十九)--SetHeaderFooter 开源摘星计划(WeOpen Star) 是由腾源会 2022 年推出的全新项目,旨在为开源人提供成长激励,为开源项目提 ...

最新文章

  1. MFC底层窗口的实现
  2. Android Studio SDK Manager 解决无法更新问题
  3. BZOJ 1924 [Sdoi2010]所驼门王的宝藏
  4. 计算理论2--可计算理论
  5. MySQL的索引及优化方案
  6. sysbench压力测试工具简介和使用(一)
  7. 非常不错的一些前端动态效果【收集】
  8. python学习if语句_python学习之if语句
  9. Ai Challenger Caption图像中文描述(2017)
  10. zabbix自动发现端口
  11. linux box 黑屏,在linux16.04上安装virturalbox的时候出现问题
  12. 《统计学习方法》——k近邻法
  13. 创建ipadWEB应用程序到主屏幕
  14. Springboot毕设项目基于springboot的小区旧物交易系统的设计与实现j8o94java+VUE+Mybatis+Maven+Mysql+sprnig)
  15. StrongShop跨境电商系统源码 支持多语言多货币
  16. 设计师必备,素材网站如千图包图免费下载的方法
  17. 图片验证码获取及验证
  18. SQL Server 下载和安装详细教程(点赞收藏)
  19. eclipse安装教程_eclipse安装教程jdk
  20. VScode中txt文件乱码解决

热门文章

  1. POJ-2728 Desert King 最优比例生成树 01分数规划/参数搜索
  2. 关于玻璃体手术的最终建议
  3. flink DDL读取kafka数据-Scala嵌入DDL形式
  4. Couldn‘t find grammar element for class javax.ws.rs.core.Response
  5. mysql的事务操作
  6. jinja2语法中{%raw%}和{{}}的等效替换
  7. Django CMS介绍(转载)
  8. @property的必要性
  9. /usr/share/virtualenvwrapper/virtualenvwrapper_lazy.sh: No such file or directory解决方案
  10. 哑编码官方代码自己的注解