从UIImageView+WebCache看起~
一般来说,SD用的比较多的应该就是这个category中的sd_set等一系列方法了。
下面咱们就一步步“CMD+点击”进去,一层层剖析吧~
/*
* url: 图片URL
* placeholder: 占位图片
* options: 加载图片的选项(包括失败重试、低优先级、仅保存在缓存中、边下载边显示、刷新缓存、进入后台继续下载、保留Cookie、允许不信任的SSL证书、高优先级、延迟显示占位图片、改变动画形象)
* progressBlock 图片下载过程中,每次接收到数据的回调的block
* completedBlock 图片下载完成回调的block
*/
-(void)sd_setImageWithURL:(NSURL*)url placeholderImage:(UIImage*)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;
一、sd_set内首先执行的是sd_cancelCurrentImageLoad,用于取消当前对象内所有下载任务
// 取消当前下载
[selfsd_cancelCurrentImageLoad];
SD会为每一个UIImageView对象拓展一个用于存放所有下载队列的NSDictionary属性,sd_cancelCurrentImageLoad方法内,会遍历NSDictionary对应key的所有队列,取消下载任务。
二、拓展属性,保存最新的url,并判断当前url是否为空
三、若url不为空,则通过SDWebImageManager单例类来获取下载队列、取消所有下载任务,并将下载队列保存
★SDWebImageManager中,根据key(将url通过MD5加密得到的字符串作为查询缓存和沙盒文件名的key),先到缓存(NSCache)中查找;缓存查找不到,再到沙盒中查找,若还找不到URL对应的图片的话,则通过imageDownloader开启下载任务(SDWebImageDownloader对象)。
★SDWebImageDownloader中,有个URLCallbacks字典,里面以URL为key,保存着对应URL的接受数据回调和下载完成回调的block。开始下载之前,会通过dispatch_barrier_sync在唯一的一个并发队列中(barrierQueue)将block保存到URLCallbacks中。(当URL已经存在,则不会重复下载,只会更新回调block)。该过程主要实现通过下面的方法:
-(void)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock andCompletedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(NSURL*)url createCallback:(SDWebImageNoParamsBlock)createCallback
★异步下载,通过SDWebImageDownloaderOperation实现(继承自NSOperation,该操作队列实现了SDWebImageOperation协议,仅有一个取消下载的代理方法)。operation添加到任务队列之前,根据options选项的高低优先级以及LIFO(后进先出原则),来决定opeartion的优先级以及设置队列的依赖。
if(options&SDWebImageDownloaderHighPriority){
operation.queuePriority=NSOperationQueuePriorityHigh;
}elseif(options&SDWebImageDownloaderLowPriority){
operation.queuePriority=NSOperationQueuePriorityLow;
}
if(wself.executionOrder==SDWebImageDownloaderLIFOExecutionOrder){
// Emulate LIFO execution order by systematically adding new operations as last operation's dependency
[wself.lastAddedOperation addDependency:operation];
wself.lastAddedOperation=operation;
}
1.在start中,利用NSURLConnection来请求图片数据,通过实现代理方法来判断图片开始下载、下载中、下载成功、失败。此外,在start最初时,判断options参数,若需要后台下载,则申请后台任务。
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
ClassUIApplicationClass=NSClassFromString(@"UIApplication");
BOOL hasApplication=UIApplicationClass&&[UIApplicationClassrespondsToSelector:@selector(sharedApplication)];
if(hasApplication&&[selfshouldContinueWhenAppEntersBackground]){
__weak __typeof__(self)wself=self;
UIApplication*app=[UIApplicationClassperformSelector:@selector(sharedApplication)];
self.backgroundTaskId=[app beginBackgroundTaskWithExpirationHandler:^{
__strong __typeof(wself)sself=wself;
if(sself){
[sself cancel];
[app endBackgroundTask:sself.backgroundTaskId];
sself.backgroundTaskId=UIBackgroundTaskInvalid;
}
}];
}
#endif
2.在NSURLConnection的代理方法 didRecieveData中,判断options选项,是否需要边下载边显示,该功能通过CoreGraphics实现。并且回调下载进度的block。
3.在NSURLConnection的代理方法 connectionDidFinishLoading中,停止当前runloop。同时根据URL中是否包含@2x,@3x字段来进行相应缩放以及进行图片解码。并且回调block。
★回调过程:SDWebImageDownloaderOperation –(通过block回调)–>SDWebImageDownloader –(通过URLCallBacks字典获取回调block回调)–>SDWebImageManager。SDWebImageManager的回调block中,通过一个SDImageCache的属性,实现了图片缓存的操作。
1.通过SDImageCache将图片缓存到内存及沙盒。(期间还会有其他操作,如根据options判断是否仅缓存到内存)。图片缓存主要通过下面的方法
[self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
2.程序进入后台或者结束时,SDImageCache都会清理内存。主要操作包括移除过期文件、将缓存保持在最大缓存的一半。