加載流程
圍繞SDWebImageManager
sd_setImageWithURL()
--> sd_internalSetImageWithURL
//首先從self的任務(wù)operations:NSMapTable 中取消任務(wù)
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
manager
--> loadImageWithURL
創(chuàng)建operation
SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
operation.manager = self;
SD_LOCK(self.runningOperationsLock);
[self.runningOperations addObject:operation];
SD_UNLOCK(self.runningOperationsLock);
開始進(jìn)入加載圖片
// Start the entry to load image from cache
[self callCacheProcessForOperation:operation url:url options:options context:context progress:progressBlock completed:completedBlock];
開始查找緩存:內(nèi)存查找 --> 硬盤查找
key: 可自定義cacheKeyFilter,默認(rèn)url.absoluteString
// First check the in-memory cache...
UIImage *image = [self imageFromMemoryCacheForKey:key];
// Second check the disk cache...
NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
如果有緩存,加載緩存串前,如果需要刷新緩存,則繼續(xù)請(qǐng)求網(wǎng)絡(luò)
// If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image
// AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
[self callCompletionBlockForOperation:operation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url];
operation = [self createDownloaderOperationWithUrl:url options:options context:context];
[self.downloadQueue addOperation:operation];
開始緩存
[self callStoreCacheProcessForOperation:operation url:url options:options context:context downloadedImage:downloadedImage downloadedData:downloadedData finished:finished progress:progressBlock completed:completedBlock];
緩存模塊
緩存配置類:SDImageCacheConfig
-
shouldCacheImagesInMemory
是否允許內(nèi)存緩存 -
shouldUseWeakMemoryCache
弱引用內(nèi)存緩存凌简,如果對(duì)象被釋放,則緩存也釋放 -
maxMemoryCount
緩存圖片個(gè)數(shù)限制恃逻,默認(rèn)0不限制 -
maxMemoryCost
最大內(nèi)存占用空間雏搂,默認(rèn)為0不限制藕施,1 pixel is 4 bytes (32 bits)
內(nèi)存緩存 SDMemoryCache
SDMemoryCache
繼承自NSCache
,通過(guò)weakCache: NSMapTable
來(lái)緩存圖片,NSMapTabel
對(duì)比NSDictionary
有更多內(nèi)存語(yǔ)義(strong、weak畔派、copy铅碍、assign)
self.weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0];
value
弱引用,當(dāng)圖片被釋放時(shí)线椰,自動(dòng)刪除此key-value
- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g {
[super setObject:obj forKey:key cost:g];
if (!self.config.shouldUseWeakMemoryCache) {
return;
}
if (key && obj) {
// Store weak cache
SD_LOCK(self.weakCacheLock);
[self.weakCache setObject:obj forKey:key];
SD_UNLOCK(self.weakCacheLock);
}
}
內(nèi)存緩存時(shí)會(huì)在NSCache
緩存一份胞谈,我們自定義的weakCache
中再緩存一份
//取出緩存
- (id)objectForKey:(id)key {
id obj = [super objectForKey:key];
if (!self.config.shouldUseWeakMemoryCache) {
return obj;
}
if (key && !obj) {
// Check weak cache
SD_LOCK(self.weakCacheLock);
obj = [self.weakCache objectForKey:key];
SD_UNLOCK(self.weakCacheLock);
if (obj) {
// Sync cache
NSUInteger cost = 0;
if ([obj isKindOfClass:[UIImage class]]) {
cost = [(UIImage *)obj sd_memoryCost];
}
[super setObject:obj forKey:key cost:cost];
}
}
return obj;
}
從NSCache
中取出緩存,在從weakCache
中取出緩存憨愉,并同步到NSCache
中
NSCache
是系統(tǒng)緩存烦绳,不受我們控制,可能會(huì)被隨時(shí)清空.
磁盤緩存
- 創(chuàng)建目錄
- 為每一個(gè)文件生成一個(gè)MD5文件名
- 清除磁盤緩存
- 刪除超過(guò)截至日期的文件
- 按訪問(wèn)或修改日期排序刪除更早的文件
下載模塊
創(chuàng)建NSOperation
生成NSURLRequest配紫,創(chuàng)建NSOperation
NSOperation<SDWebImageDownloaderOperation> *operation = [[operationClass alloc] initWithRequest:request inSession:self.session options:options context:context];
控制任務(wù)優(yōu)先級(jí),先進(jìn)先出或者后進(jìn)先出
if (self.config.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
// Emulate LIFO execution order by systematically adding new operations as last operation's dependency
[self.lastAddedOperation addDependency:operation];
self.lastAddedOperation = operation;
}
SDWebImageDownloaderOperation
重寫了start
方法,當(dāng)[self.downloadQueue addOperation:operation];
時(shí)径密,自動(dòng)執(zhí)行operation
的start
方法,[dataTask resume]
則開始下載任務(wù)
//如果session不存在則創(chuàng)建session
/**
* Create the session for this task
* We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate
* method calls and completion handler calls.
*/
session = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:nil];
//生成dataTask
self.dataTask = [session dataTaskWithRequest:self.request];
//執(zhí)行
[self.dataTask resume];
NSURLSessionDataDelegate
,NSURLSessionTaskDelegate
代理方法躺孝,接收下載的數(shù)據(jù)
圖片編解碼
有時(shí)間在搞