日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

SDWebImage源码阅读(九)SDWebImageDownloader

發(fā)布時(shí)間:2023/12/20 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SDWebImage源码阅读(九)SDWebImageDownloader 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  這篇學(xué)習(xí) SDWebImageDownloader 這個(gè)類。

  首先依然是看 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 };

  這是一個(gè) NS_OPTIONS 的枚舉,用來(lái)表示不同的下載選項(xiàng)。

  當(dāng)需要給某個(gè)功能添加 Options 的時(shí)候或者對(duì)不同的情況分類的時(shí)候,一般使用枚舉來(lái)實(shí)現(xiàn)。

  提供的了 9 種不同的情況,且他們都是可以根據(jù)不同的需求進(jìn)行匹配選擇。這里的給每一個(gè)選項(xiàng)賦值使用了掩碼,"<< " 表示左移操作,>> 表示右移操作。1<<0 ?表示把 1 轉(zhuǎn)化為二進(jìn)制然后整體左移 0 位,沒(méi)有變化當(dāng)然還是 1。1 << 1 則是把 1 轉(zhuǎn)化為二進(jìn)制是 0b0000 0001,把它整體左移 1 位是 0b0000 0010 它轉(zhuǎn)化為 10 進(jìn)制是 2,即左移一位表示在原來(lái)的值上乘以 2 。所以上面表示的枚舉值自上而下分別是 1 左移 0 位至 8 位,表示的 NSUInteger 分別是: 0b0000 0001、0b0000 0010、0b0000 0100、0b0000 1000、0b0001 0000、0b0010 0000、0b0100 0000、0b1000 000 ...

  所以在判斷 self.option 是否是某個(gè)枚舉值的時(shí)候,直接拿 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 };

  這是一個(gè) NS_ENUM 的枚舉,用來(lái)表示下載時(shí)數(shù)據(jù)被調(diào)用的順序。

  FIFO (first-in-first-out 先進(jìn)先出)、LIFO (last-in-first-out 后進(jìn)先出),下載圖像一般按照放入隊(duì)列中的順序依次進(jìn)行,不過(guò)這里同時(shí)也支持后放入隊(duì)列任務(wù)的先下載的操作。

  一個(gè)下載管理器應(yīng)該這樣管理下載,肯定有一個(gè)下載列表,可以假定這個(gè)列表保存在一個(gè)數(shù)組中,正常情況下應(yīng)該每次取出數(shù)組中第1個(gè)元素來(lái)下載,這就是 FIFO (先進(jìn)先出)。那么要改為 LIFO (后進(jìn)先出),應(yīng)該是針對(duì)某一個(gè)下載的,不應(yīng)該是把取出數(shù)據(jù)的順序改為從數(shù)組的最后一個(gè)元素取出。

?

  SDWebImageDownloadStartNotification、

SDWebImageDownloadStopNotification

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

  它們兩個(gè)的賦值在 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);

  命名兩個(gè) block ,一個(gè)是下載進(jìn)度的 block,一個(gè)下載完成的 block。

?

  SDHTTPHeadersDictionary、

SDHTTPHeadersMutableDictionary

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

  命名兩個(gè) key 和 value 都是字符串,用于 SDHTTPHeaders 的字典。

?

  SDWebImageDownloaderHeadersFilterBlock

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

  這個(gè) block 用來(lái)自定義請(qǐng)求頭。

?

  SDWebImageDownloadToken

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

  這個(gè)類表示與每一個(gè)下載相關(guān)的?token,能用于取消一個(gè)下載。

  SDWebImageDownloadToken?作為每一個(gè)下載的唯一身份標(biāo)識(shí)。SDWebImageDownloader?和我們平時(shí)開(kāi)發(fā)中的下載還是有不一樣的地方的,它弱化了下載過(guò)程,比較強(qiáng)調(diào)的是下載結(jié)果。不支持?jǐn)帱c(diǎn)下載(當(dāng)然這可能沒(méi)有必要)。?

  如果需要設(shè)計(jì)一個(gè)自己的下載管理者,就應(yīng)該設(shè)計(jì)一個(gè)類似 SDWebImageDownloadToken?這樣的下載對(duì)象封裝類,需要的所有信息,都能在這個(gè)對(duì)象中獲取。

  

  SDWebImageDownloader

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

  異步下載專用的圖像加載優(yōu)化。

?

  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;

   是否解壓圖像,解壓下載和緩存的圖像可以提高性能,但是會(huì)消耗大量的內(nèi)存,默認(rèn)是 YES,如果因消耗內(nèi)存過(guò)大可以設(shè)置為 NO。

?

  maxConcurrentDownloads

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

  表示并發(fā)下載的最大數(shù)量。

?

  currentDownloadCount

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

  顯示當(dāng)前仍需要下載的下載量。

?

  downloadTimeout

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

  下載操作的超時(shí)時(shí)間,單位是秒。默認(rèn)是 15 秒。

?

  executionOrder

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

  更改下載操作的執(zhí)行順序。默認(rèn)是 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;

  設(shè)置默認(rèn)的 URL 憑據(jù),以設(shè)置請(qǐng)求操作。

?

  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;

  設(shè)置篩選器以選擇用于下載圖像 http 請(qǐng)求的標(biāo)頭。該 block 將被調(diào)用為每個(gè)下載圖像請(qǐng)求,返回一個(gè) NSDictionary 作為相應(yīng)的 http 請(qǐng)求頭。

  

  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;

  使用一個(gè) NSURLSessionConfiguration 實(shí)例做參數(shù),創(chuàng)建一個(gè)具有指定的 NSURLSessionConfiguration ?的下載實(shí)例。

  使用 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;

  設(shè)置附加到每個(gè)下載 HTTP 請(qǐng)求的 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 創(chuàng)建一個(gè) SDWebImageDownloader 異步下載實(shí)例。

  當(dāng)圖像下載完成和下載錯(cuò)誤時(shí),將通知代理。

?

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;

  取消先前排隊(duì)使用的下載。

?

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

  設(shè)置下載隊(duì)列掛起狀態(tài)。

?

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

  取消隊(duì)列中的所有下載操作。

?

  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 下載的隊(duì)列。

  NSOperation *lastAddedOperation 用于紀(jì)錄最后添加的操作。

  Class operationClass ?支持自定義的操作類。

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

  SDHTTPHeadersMutableDictionary *HTTPHeaders HTTP 請(qǐng)求頭。

  dispatch_queue_t barrierQueue 這個(gè)隊(duì)列是用于序列化所有下載操作的網(wǎng)絡(luò)響應(yīng)的處理在一個(gè)單一的隊(duì)列。

  NSURLSession *session 數(shù)據(jù)任務(wù)將運(yùn)行的的會(huì)話。

?

  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 這兩個(gè)方法:

  執(zhí)行時(shí)機(jī): load 在程序運(yùn)行后立即執(zhí)行 initialize 在類的方法第一次被調(diào)用時(shí)執(zhí)行

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

  類別中的定義: load 全部執(zhí)行,但后于類中的方法,initialize 覆蓋類中的方法,只執(zhí)行一個(gè)

?

  上面 initialize 里面的方法實(shí)現(xiàn),是為了在圖片下載的時(shí)候綁定一個(gè) SDNetworkActivityIndicator,當(dāng)引入 SDNetworkActivityIndicator 類的時(shí)候,先獲得 SDNetworkActivityIndicator 的單例類,然后首先移除之前添加的?SDWebImageDownloadStartNotification、SDWebImageDownloadStopNotification?的通知,然后重新添加 Start 和 Stop 通知,當(dāng) Start 的時(shí)候執(zhí)行 startActivity 方法,當(dāng) Stop 的時(shí)候執(zhí)行 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 }

  單例方法實(shí)現(xiàn)。

  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 }

  自定義初始化方法實(shí)現(xiàn)。對(duì)上面提到的屬性默認(rèn)賦值。SDWebImageDownloaderOperation 為自定義類、默認(rèn)解壓、下載順序 FIFO、并發(fā)下載是 6、15 秒超時(shí)等等。

  _HTTPHeaders 比較特殊:  

  "image/webp,image/*;q=0.8"?是什么意思??image/webp?是 web 格式的圖片,q=0.8?指的是權(quán)重系數(shù)為0.8,q 的取值范圍是 0 - 1, 默認(rèn)值為 1,q 作用于它前邊分號(hào)(;)前邊的內(nèi)容。在這里,image/webp,image/*;q=0.8?表示優(yōu)先接受?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 方法實(shí)現(xiàn)

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 }

  每一個(gè)圖片的 URL 都會(huì)被作為對(duì)應(yīng)的下載操作的唯一標(biāo)識(shí),每一個(gè)下載都會(huì)綁定一個(gè) progressBlock 和一個(gè) completeBlock,最后還用這個(gè) URL 與 SDWebImageDownloaderOperation 建立聯(lián)系。

  該 URL 將被作為回調(diào)字典的關(guān)鍵所以不能為 nil。如果是 nil 則直接調(diào)用沒(méi)有數(shù)據(jù)和 image 的完成的 block。

  定義一個(gè) __block 修飾的 SDWebImageDownloadToken 實(shí)例 token。

  在 self.barrierQueue 隊(duì)列中使用?dispatch_barrier_sync?同步執(zhí)行:

  使用 URL 從 self.URLOperations 中獲取指定的 SDWebImageDownloaderOperation。

  如果 operation 不存在:

  operation = createCallback(); 執(zhí)行這個(gè) block。

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

  operation 的 ?completionBlock 的實(shí)現(xiàn),從 self.URLOperations 里面刪除 URL 對(duì)應(yīng)的 SDWebImageDownloaderOperation。

  把完成的 block 和 進(jìn)度的 block 添加進(jìn) operation 的 _callbackBlocks 里面。

  downloadOperationCancelToken 是一個(gè)存放了完成 block 和進(jìn)度 block 的字典。

  給 token 賦值。

  返回 token。

?

  創(chuàng)建 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。

  調(diào)用上面的返回 Token 的方法:

  主要看 createCallback 的實(shí)現(xiàn):

  在 block 內(nèi)部使用 __strong 修飾 self。

  設(shè)置超時(shí)時(shí)間。

  創(chuàng)建 request,主要注意緩存策略的選擇。

  給 ?request 的 ?HTTPShouldHandleCookies 和 HTTPShouldUsePipelining 賦值。

  設(shè)置請(qǐng)求頭。

  創(chuàng)建 SDWebImageDownloaderOperation。

  給 SDWebImageDownloaderOperation 設(shè)置 urlCredential。

  給 SDWebImageDownloaderOperation 設(shè)置操作的優(yōu)先級(jí)。

  把操作添加進(jìn)隊(duì)列里面。

  根據(jù) _executionOrder 是先進(jìn)先出還是先進(jìn)后出,給操作添加依賴。

?

  取消某個(gè)操作

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 }

  

  設(shè)置隊(duì)列掛起

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 在初始化的時(shí)候把 delegate 設(shè)置為了當(dāng)前類,且 SDWebImageDownloader 遵守?NSURLSessionTaskDelegate、NSURLSessionDataDelegate?協(xié)議,當(dāng)使用 self.session 請(qǐng)求數(shù)據(jù),收到響應(yīng)的的時(shí)候,會(huì)調(diào)用 SDWebImageDownloader.m 里面實(shí)現(xiàn)的代理方法,然后在調(diào)用 SDWebImageDownloaderOperation 里面的代理方法。第一次見(jiàn)這樣的設(shè)計(jì),作者的目的是為了共用一個(gè) 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

?

轉(zhuǎn)載于:https://www.cnblogs.com/chmhml/p/6956727.html

總結(jié)

以上是生活随笔為你收集整理的SDWebImage源码阅读(九)SDWebImageDownloader的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。