SDWebImage源码分析

SDWebImageManager -- 单例

1 - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {

1.1 id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:

^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL)

1.2 [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];

SDWebImageManager  1 - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
  2                                          options:(SDWebImageOptions)options
  3                                         progress:(SDWebImageDownloaderProgressBlock)progressBlock
  4                                        completed:(SDWebImageCompletionWithFinishedBlock)completedBlock {
 25     __block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
 41     @synchronized (self.runningOperations) {
 42         [self.runningOperations addObject:operation];
 43     }
 44     NSString *key = [self cacheKeyForURL:url];
 45
 46     operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key                                          done:^(UIImage *image, SDImageCacheType cacheType)     {
 47         if (operation.isCancelled) { 49                 [self.runningOperations removeObject:operation];
 52             return;
 53         }
 55         if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]))         {
 56             if (image && options & SDWebImageRefreshCached) {
 57                 dispatch_main_sync_safe(^{
 58                     // If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
 59                     // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
 60                     completedBlock(image, nil, cacheType, YES, url);
 61                 });
 62             } 79             id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
 80                 if (weakOperation.isCancelled) {
 81                     // Do nothing if the operation was cancelled
 82                     // See #699 for more details
 83                     // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data
 84                 }
 85                 else if (error) { 88                      completedBlock(nil, error, SDImageCacheTypeNone, finished, url);
 94              [self.failedURLs addObject:url]; 97                 }
 98                 else {
 99                     BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
101                     if (options & SDWebImageRefreshCached && image && !downloadedImage) {
102                         // Image refresh hit the NSURLCache cache, do not call the completion block
103                     }
104                             // NOTE: We don‘t call transformDownloadedImage delegate method on animated images as most transformation code would mangle it
105                     else if (downloadedImage && !downloadedImage.images && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
106                         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
107                             UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
109                             if (transformedImage && finished) {
110                                 BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
111                                 [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk];
112                             }116                                     completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);119                         });
120                     }
121                     else {
122                         if (downloadedImage && finished) {
123                             [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
124                         }128                                 completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);131                     }
132                 }
134                 if (finished) {136                         [self.runningOperations removeObject:operation];138                 }
139             }];
140             operation.cancelBlock = ^{
141                 [subOperation cancel];144                     [self.runningOperations removeObject:weakOperation];146             };
147         }
148         else if (image) {151                     completedBlock(image, nil, cacheType, YES, url);155                 [self.runningOperations removeObject:operation];157         }
158         else {
159             // Image not in cache and download disallowed by delegate162                     completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);166                 [self.runningOperations removeObject:operation];168         }
169     }];
170
171     return operation;
172 }
SDImageCache 1 - (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock {

11     // First check the in-memory cache...
12     UIImage *image = [self imageFromMemoryCacheForKey:key];
13     if (image) {
14         doneBlock(image, SDImageCacheTypeMemory);
15         return nil;
16     }
17
18     NSOperation *operation = [NSOperation new];
19     dispatch_async(self.ioQueue, ^{
20         if (operation.isCancelled) {
21             return;
22         }
23
24         @autoreleasepool {
25             UIImage *diskImage = [self diskImageForKey:key];
26             if (diskImage) {
27                 CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale;
28                 [self.memCache setObject:diskImage forKey:key cost:cost];
29             }
30
31             dispatch_async(dispatch_get_main_queue(), ^{
32                 doneBlock(diskImage, SDImageCacheTypeDisk);
33             });
34         }
35     });
36
37     return operation;
38 }
SDWebImageDownloader
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock {
    __block SDWebImageDownloaderOperation *operation;
    [self addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^{
            timeoutInterval = 15.0;
        // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url                                          cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) 

                                      timeoutInterval:timeoutInterval]; operation = [[SDWebImageDownloaderOperation alloc] initWithRequest:request options:options progress:^(NSInteger receivedSize, NSInteger expectedSize) { SDWebImageDownloaderProgressBlock callback = callbacks[kProgressCallbackKey]; if (callback) callback(receivedSize, expectedSize); } completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey]; if (callback) callback(image, data, error, finished); } cancelled:^{ [sself removeCallbacksForURL:url]; }]; [wself.downloadQueue addOperation:operation]; [wself.lastAddedOperation addDependency:operation]; }]; return operation; }

- (void)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock andCompletedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(NSURL *)url createCallback:(SDWebImageNoParamsBlock)createCallback {    dispatch_barrier_sync(self.barrierQueue, ^{        BOOL first = NO;        if (!self.URLCallbacks[url]) {            self.URLCallbacks[url] = [NSMutableArray new];//第一次请求该url,新建URLCallbacks数组            first = YES;//标示是第一次        }

        // Handle single download of simultaneous download request for the same URL        NSMutableArray *callbacksForURL = self.URLCallbacks[url];        NSMutableDictionary *callbacks = [NSMutableDictionary new];        if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy];//保存progressBlock        if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy];//保存completedBlock        [callbacksForURL addObject:callbacks];//保存至URLCallbacks        self.URLCallbacks[url] = callbacksForURL;保存至self.URLCallbacks        if (first) {            createCallback();//第一次请求该url,执行createCallback        }    });}
 
时间: 2024-10-08 11:02:31

SDWebImage源码分析的相关文章

SDWebImage 源码分析 --加载gif图片

n年关了,马上放假,终于把手头上的事情告一段落,连续发布了3个app,我也是醉了. 终于有了点时间.想研究下SDWebImage是怎么加载gif图片的. 一直很好奇. 现在开始. 1,首先我们看下SDWebImage是怎么加载gif的. faceButton.image = [UIImage sd_animatedGIFNamed:[NSString stringWithFormat:@"CHATA_%d",i - 46]]; sd_animatedGIFNamed是SDWebImag

【原】SDWebImage源码阅读(三)

[原]SDWebImage源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1.SDWebImageDownloader中的downloadImageWithURL 我们来到SDWebImageDownloader.m文件中,找到downloadImageWithURL函数.发现代码不是很长,那就一行行读.毕竟这个函数大概做什么我们是知道的.这个函数大概就是创建了一个SDWebImageSownloader的异步下载器,根据给定的URL下载image. 先映入眼帘的

【原】SDWebImage源码阅读(五)

[原]SDWebImage源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 前面的代码并没有特意去讲SDWebImage的缓存机制,主要是想单独开一章节专门讲解缓存.之前我们也遇到一些缓存的属性和方法,比如storeImage.queryDiskCacheForKey.memCache等等. SDWebImage的缓存分为两个部分,一个内存缓存,使用NSCache实现,另一个就是硬盘缓存(disk),使用NSFileManager实现. 不过这么多函数,

【原】SDWebImage源码阅读(二)

[原]SDWebImage源码阅读(二) 本文转载请注明出处 —— polobymulberry-博客园 1. 解决上一篇遗留的坑 上一篇中对sd_setImageWithURL函数简单分析了一下,还留了一些坑.不过因为我们现在对这个函数有一个大概框架了,我们就按顺序一个个来解决. 首先是这一句代码: objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 就是给UIImageVi

SDWebImage源码阅读-第三篇

这一篇讲讲不常用的一些方法. 1 sd_setImageWithPreviousCachedImageWithURL: placeholderImage: options: progress: completed: 取得上次缓存的图片,然后作为占位图的参数再次进行一次图片设置. - (void)sd_setImageWithPreviousCachedImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options

SDWebImage源码解析(二)

源码来源: https://github.com/rs/SDWebImage 版本: 3.7 SDWebImage是一个开源的第三方库,它提供了UIImageView的一个分类,以支持从远程服务器下载并缓存图片的功能.它具有以下功能: 提供UIImageView的一个分类,以支持网络图片的加载与缓存管理 一个异步的图片加载器 一个异步的内存+磁盘图片缓存 支持GIF图片 支持WebP图片 后台图片解压缩处理 确保同一个URL的图片不被下载多次 确保虚假的URL不会被反复加载 确保下载及缓存时,主

iOS常用框架源码分析

SDWebImage NSCache 类似可变字典,线程安全,使用可变字典自定义实现缓存时需要考虑加锁和释放锁 在内存不足时NSCache会自动释放存储的对象,不需要手动干预 NSCache的key不会被复制,所以key不需要实现NSCopying协议 第三方框架 网络 1.PPNetworkHelper 对AFNetworking 3.x 与YYCache的二次封装 简单易用,包含了缓存机制,控制台可以直接打印json中文字符 2..YTKNetwork 猿题库研发团队基于AFNetworki

TeamTalk源码分析之login_server

login_server是TeamTalk的登录服务器,负责分配一个负载较小的MsgServer给客户端使用,按照新版TeamTalk完整部署教程来配置的话,login_server的服务端口就是8080,客户端登录服务器地址配置如下(这里是win版本客户端): 1.login_server启动流程 login_server的启动是从login_server.cpp中的main函数开始的,login_server.cpp所在工程路径为server\src\login_server.下表是logi

Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)

1 背景 还记得前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>中关于透过源码继续进阶实例验证模块中存在的点击Button却触发了LinearLayout的事件疑惑吗?当时说了,在那一篇咱们只讨论View的触摸事件派发机制,这个疑惑留在了这一篇解释,也就是ViewGroup的事件派发机制. PS:阅读本篇前建议先查看前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>,这一篇承接上一篇. 关于View与ViewGroup的区别在前一篇的A