今天總計(jì)一下SDWebImage核心模塊之下載模塊。下載模塊主要包括兩個(gè)類SDWebImageDownloader和SDWebImageDownloaderOperation。其中SDWebImageDownloader負(fù)責(zé)對(duì)所有下載任務(wù)的管理,SDWebImageDownloaderOperation負(fù)責(zé)具體的一個(gè)下載任務(wù)的執(zhí)行。另外為了拓展下載功能,還支持實(shí)現(xiàn)SDWebImageDownloaderOperationInterface協(xié)議來(lái)自定義SDWebImageDownloaderOperation,根據(jù)需求自定義下載行為。
SDWebImageDownloader內(nèi)部構(gòu)成
SDWebImageDownloader內(nèi)部持有一個(gè)下載隊(duì)列downloadQueue用于管理所有下載操作,一個(gè)緩存字典緩存所有的SDWebImageDownloaderOperation下載操作,一個(gè)httpheader的設(shè)置字典設(shè)置下載的請(qǐng)求頭信息,兩個(gè)信號(hào)鎖保證緩存字典和header頭字典的安全操作。同時(shí)持有一個(gè)下載的session和下載session的對(duì)應(yīng)的配置文件NSURLSessionConfiguration。
SDWebImageDownloader主要方法
- (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;
NSTimeInterval timeoutInterval = sself.downloadTimeout;
if (timeoutInterval == 0.0) {
timeoutInterval = 15.0;
}
// In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise
//NSURLRequest生成
NSURLRequestCachePolicy cachePolicy = options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url
cachePolicy:cachePolicy
timeoutInterval:timeoutInterval];
//設(shè)置cookie信息
request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
request.HTTPShouldUsePipelining = YES;
//設(shè)置header信息
if (sself.headersFilter) {
request.allHTTPHeaderFields = sself.headersFilter(url, [sself allHTTPHeaderFields]);
}
else {
request.allHTTPHeaderFields = [sself allHTTPHeaderFields];
}
//組建SDWebImageDownloaderOperation
SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options];
operation.shouldDecompressImages = sself.shouldDecompressImages;
//設(shè)置加密信息
if (sself.urlCredential) {
operation.credential = sself.urlCredential;
} else if (sself.username && sself.password) {
operation.credential = [NSURLCredential credentialWithUser:sself.username password:sself.password persistence:NSURLCredentialPersistenceForSession];
}
//設(shè)置優(yōu)先級(jí)
if (options & SDWebImageDownloaderHighPriority) {
operation.queuePriority = NSOperationQueuePriorityHigh;
} else if (options & SDWebImageDownloaderLowPriority) {
operation.queuePriority = NSOperationQueuePriorityLow;
}
//設(shè)置隊(duì)列
if (sself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
// Emulate LIFO execution order by systematically adding new operations as last operation's dependency
[sself.lastAddedOperation addDependency:operation];
sself.lastAddedOperation = operation;
}
return operation;
}];
}
此方法用于對(duì)外的暴露,實(shí)際上進(jìn)行了SDWebImageDownloaderOperation的生成的相關(guān)設(shè)置工作。NSURLRequest生成并設(shè)置的header信息、cookie信息設(shè)置。NSURLRequest、session、配置options生成DownloaderOperation. DownloaderOperation設(shè)置加密、優(yōu)先級(jí)、隊(duì)列。最后通過(guò)addProgressCallback方法將operation緩存,并添加到操作隊(duì)列中addOperation。
SDWebImageDownloader下載選項(xiàng)
SDWebImageDownloader提供了很多下載選項(xiàng),可以根據(jù)情況進(jìn)行配置。如設(shè)置下載優(yōu)先級(jí)、進(jìn)度、后臺(tái)下載,圖片縮放等,同時(shí)支持先進(jìn)先出,先進(jìn)后出的下載方式。
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
//下載低優(yōu)先級(jí)
SDWebImageDownloaderLowPriority = 1 << 0,
//下載高優(yōu)先級(jí)
SDWebImageDownloaderHighPriority = 1 << 7,
// 帶有進(jìn)度
SDWebImageDownloaderProgressiveDownload = 1 << 1,
//默認(rèn)不使用URLCache
SDWebImageDownloaderUseNSURLCache = 1 << 2,
//如果圖片是在NSURLCAche中讀取時(shí),調(diào)用completion block時(shí),返回nil,配合SDWebImageDownloaderUseNSURLCache使用
SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
//支持后臺(tái)下載
SDWebImageDownloaderContinueInBackground = 1 << 4,
//支持NSHTTPCookieStore的cookie信息,進(jìn)而設(shè)置NSMutableURLRequest.HTTPShouldHandleCookies=YES
SDWebImageDownloaderHandleCookies = 1 << 5,
//允許不信任SSL證書(shū)
SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6,
//縮放大圖片
SDWebImageDownloaderScaleDownLargeImages = 1 << 8,
};
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
//先進(jìn)先出
SDWebImageDownloaderFIFOExecutionOrder,
//先進(jìn)后出
SDWebImageDownloaderLIFOExecutionOrder
};
SDWebImageDownloader默認(rèn)配置
1.解壓縮shouldDecompressImages:默認(rèn)情況下,圖片下載下來(lái)就解壓縮,這是拿空間換時(shí)間的做法,讓圖片在使用時(shí)能更快的加載。
2.最大下載數(shù)maxConcurrentDownloads:此屬性實(shí)質(zhì)是設(shè)置下載隊(duì)列(NSOperationQueue)的最大數(shù)并發(fā)數(shù)。
3.當(dāng)前最大下載數(shù)currentDownloadCount:當(dāng)前下載隊(duì)列中未執(zhí)行完畢的操作個(gè)數(shù)
4.下載超時(shí)時(shí)間downloadTimeout:默認(rèn)設(shè)置為15秒
5.下載隊(duì)列executionOrder:默認(rèn)是先進(jìn)先出,先到先下載的隊(duì)列
SDWebImageDownloaderOperation
SDWebImageDownloaderOperation持有NSURLSessionTask和NSURLRequest,在start方法中創(chuàng)建網(wǎng)絡(luò)請(qǐng)求并執(zhí)行,在URLSession:task:didCompleteWithError:中進(jìn)行數(shù)據(jù)的整合處理,反饋給外部。
總結(jié):
SDWebImage的下載管理模塊SDWebImageDownloader采用了NSOperationQueue來(lái)管理隊(duì)列,而沒(méi)有使用更加高效的GCD來(lái)完成。這是因?yàn)橄螺d的業(yè)務(wù)的復(fù)雜性比較高,如優(yōu)先級(jí)設(shè)置、取消操作、操作狀態(tài)的監(jiān)控、操作的依賴性,這些如果用GCD來(lái)封裝的話,最后的結(jié)果就是寫(xiě)出一個(gè)NSOperationQueue出來(lái),所以我猜作者肯定想何必再封裝造輪子呢,直接使用NSOperationQueue得了。