SDWebImage源码解析

SDWebImage是通过类别的方式给UIImageview 和UIButton 等类进行扩展,方便用户下载图片并渲染到视图上的开源库,解读该开源代码的时候SDWebImage的版本是

3.7.5。

0x 01、 动态关联一个NSURL的属性到UIImageView,仅用于应用层需要返回sd_imageURL的时候读取,代码如下:

 objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 

0x 02 、使用一个SDWebImageManager的单例.sharedManager开启一个SDWebImageCombinedOperation 操作下载,开启该下载之前,先去之前缓存过的下载失败的

 NSMutableSet *failedURLs集合里去查找,当前要下载的url是否被包含,若被包含,则直接返回失败。

0x 03 、若0x 02没有返回,则把SDWebImageCombinedOperation加入到一个runningOperations的数组里,用[url

absoluteString]作为key值,去SDImageCache里查询。以key为关键字的图片。

1 [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType){}] 

0x 04、在SDImageCache查询的时候,先去查询以key为关键字的图片是否存在内存缓中,若内存缓存中做存在,则返回查找成功。

1  UIImage *image = [self imageFromMemoryCacheForKey:key];
2     if (image) {
3         doneBlock(image, SDImageCacheTypeMemory);
4         return nil;
5     }

0x 05、若内存缓存中没有找到,则到硬盘存储中去继续查询关键字为key的图片,在硬盘里查找的时候,启动一个GCD的串行队列_ioQueue查找,若没有查找到则返回查找失败,若查找到,先把查找到的图片缓存到内存中去,再返回。

关键代码:

 1 // 此处创建一个串行的GCD队列查找硬盘中的图片
 2  _ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
 3 
 4 NSOperation *operation = [NSOperation new];
 5     dispatch_async(self.ioQueue, ^{
 6         if (operation.isCancelled) {
 7             return;
 8         }
 9 
10         @autoreleasepool {
11             UIImage *diskImage = [self diskImageForKey:key];
12             //缓存查找到的图片到内存中去
13             if (diskImage && self.shouldCacheImagesInMemory) {
14                 NSUInteger cost = SDCacheCostForImage(diskImage);
15                 [self.memCache setObject:diskImage forKey:key cost:cost];
16             }
17            //返回查找到的图片
18             dispatch_async(dispatch_get_main_queue(), ^{
19                 doneBlock(diskImage, SDImageCacheTypeDisk);
20             });
21         }
22     });

0x 06、 若内存和硬盘中都没有查找到图片,则在SDWebImageDownloader里启动一个SDWebImageDownloaderOperation的

operation开始下载,SDWebImageDownloaderOperation类继承自NSOperation类,所以可以检查一下下载的时候是否是先进先出,如果不是,则把最后一次添加的

operation添加依赖到当前operation之后执行。

关键代码:

 1      operation = [[wself.operationClass alloc] initWithRequest:request
 2                                                           options:options
 3                                                          progress:^(NSInteger receivedSize, NSInteger expectedSize) {}];//启动一个operation 任务
 4 
 5          //把一个downloadQueue任务添加到一个NSOperationQueue里去
 6         [wself.downloadQueue addOperation:operation];
 7         //若不是先进先出的任务,则添加前一个任务依赖后一个任务,一般情况下默认是先进先出,不用处理
 8         if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
 9             // Emulate LIFO execution order by systematically adding new operations as last operation's dependency
10             [wself.lastAddedOperation addDependency:operation];
11             wself.lastAddedOperation = operation;
12         }

0x 07、 在SDWebImageDownloaderOperation 内部启动一个NSURLConnection请求来下载图片。下载完成之后,解码图片,然后缓存到内存和硬盘中去(是否缓存到硬盘中去取决于用户设置的options选项)。

关键代码:

   if (!image.images) {
                if (self.shouldDecompressImages) {
                    image = [UIImage decodedImageWithImage:image];
                }
            }//解码图片
//缓存图片到内存和硬盘中去。
  [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];

0x 08 返回图片给主线程,刷新视图控件。

补充一下,一般图片默认缓存在目录下(Library/Caches/default)

1   NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
2     return [paths[0] stringByAppendingPathComponent:fullNamespace];
原文地址:https://www.cnblogs.com/yanyan1119/p/5311985.html