SDWebImage源代码阅读(一)
2016-09-13 01:49
183 查看
SDWebImage源代码阅读(一)
首先看了张朝龙的博客关于SDwebImage的阅读,然后自己也去看了一下SDWebImage的源代码,以下结合多个方面给出自己的理解为什么我们要使用SDWebImage去缓存图片:
流量很贵APP不缓存图片,每次都要重新去下载图片
所以这样APP就变得很费钱
花钱的东西在天朝是不招人喜欢的,天朝子民都喜欢破解,所以我们需要尽量节约他们的流量
使用SDWebImage可以很好地缓存图片,这样就做到APP不会被天朝的子民讨厌的第一步了
怎么用SDWebImage(GitHub上的,自己的理解和翻译):
首先引用:#import
然后:
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
带闭包的:
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { ... completion code here ... }];
注意:如果你的图像加载在完成前取消,无论成功还是是失败都会调用这个闭包
SDWwebImageManager:
SDWebImageManager *manager = [SDWebImageManager sharedManager]; [manager downloadImageWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) { // progression tracking code } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (image) { // do something with image } }];
单独使用异步图片下载:
SDWebImageDownloader *downloader = [SDWebImageDownloader sharedDownloader]; [downloader downloadImageWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) { // progression tracking code } completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { if (image && finished) { // do something with image } }];
单独使用异步图片缓存
SDImageCache使用内存或者磁盘保存图片,磁盘高速缓存的读写是异步操作,所以不会对界面造成延迟用SDImageCache通过key来获取图片,如果图片为nil,表示目前没有该图片的缓存
SDImageCache *imageCache = [[SDImageCache alloc] initWithNamespace:@"myNamespace"]; [imageCache queryDiskCacheForKey:myCacheKey done:^(UIImage *image) { // image is not nil if image was found }];
如果你只想在内存中查找,可以使用方法
imageFromMemoryCacheForKey:
用SDImageCache通过key来保存图片
[[SDImageCache sharedImageCache] storeImage:myImage forKey:myCacheKey];
如果你只想把图片储存在内存中可以使用方法
storeImage:forKey:toDisk:并设置toDisk的参数来完成
使用缓存关键词过滤
有时你也许不想使用图像URL作为缓存键,因为URL可能是动态的(i.e.: for access control purpose)。SDWebImageManager provides a way to set a cache key filter that takes the NSURL as input, and output a cache key NSString(SDWebImageManager提供给我们一个方法去设置一个缓存过滤器,我们将URL给它,然后它换给我们是key的字符串(URL))
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL *url) { url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path]; return [url absoluteString]; }; // Your app init code... return YES; }
源码阅读:
我们使用频率最高的,也是简单便捷的sd_setImageWithURL:···函数,所以我们从这里看
UIImageView+WebCache:
只要是sd_setImageWithURL:无论之后的参数是什么都会执行
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock { }
参数的省略都是对此函数的参数的变化,这里是显示了SDwebImage库DRY做的非常好,值得去学习的不只是他的代码,还有他的一些规范。
先看该函数的参数:
url:大家都知道的placeholder:相当于textfield那种没有文字输出的状态的背景文字,这里是图片没有加载完毕是的背景图片
options:这里是一些下载图片的配置
SDWebImageRetryFailed 失败重试,取消黑名单,默认情况:失败后将网址列入黑名单,不再加载
SDWebImageLowPriority 低优先级,默认情况,图像下载在用户界面交互过程中仍然继续,此标志禁用此功能,(e:UIScrollView滑动的情况下,下载会延迟)
SDWebImageCacheMemoryOnly 只用内存缓存图片,此标志禁用磁盘缓存
SDWebImageProgressiveDownload 此标志可进行渐进式下载,图像显示在下载过程中逐步显示像一个浏览器一样。默认情况下,图像只显示一次完全下载。
SDWebImageRefreshCached 刷新缓存。即使图像已经被缓存了,以HTTP响应缓存控制为主,如果需要的话,从远程位置刷新图像。磁盘缓存将被NSURLCache操作而不是SDWebImage,所以会导致轻微的性能退化。此选项有助于处理在同一个请求的后面改变的图像,例如脸谱网图形的应用程序的配置文件。如果一个缓存的图像被刷新,完成块被执行一次与缓存的图像,并再次执行与最终图像。如果你不能使你的URL是静态的,请使用此标志。
SDWebImageContinueInBackground 在后台继续执行。在IOS4以上的系统,如果应用程序在后台执行时想继续下载图片,我们需要向系统请求。在后台完成请求,需要花更多的时间,如果后台任务过期,操作将被取消
SDWebImageHandleCookies 设置此项,我们会将cookies存储在NSHTTPCookieStore里,相当于设置
NSMutableURLRequest.HTTPShouldHandleCookies = YES;
SDWebImageAllowInvalidSSLCertificates 使允许不受信任的SSL证书,用于测试目的,在生产中谨慎使用。
SDWebImageHighPriority 默认情况下,图片的加载是在队列中的,此标志将其移动到队列的前面
SDWebImageDelayPlaceholder 默认情况下,在图片加载的时候占位符图片已经被加载了,此标志表示会在图片已经加载完毕后,延迟占位符的加载
SDWebImageTransformAnimatedImage 我们通常不对动画图片执行transformDownloadedImage的委托方法,因为大部分转码会破坏它们,此标志是用来对它们进行转码的
SDWebImageAvoidAutoSetImage 在默认情况下,图片下载后会马上添加在UIImageView上。但是在某些情况下,我们手动设置这个图片(e:给图片应用过滤器或者添加交叉淡出的动画),使用这个标志,我们可以在图片加载成功的时候对该图片进行手工设置
progressBlock 图片加载过程中执行的闭包
completedBlock 图片加载完成执行的闭包(不管加载是否成功)
typedef void(^SDWebImageCompletionBlock)
(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
该函数完成后的闭包,首先会执行
[self sd_cancelCurrentImageLoad];
从downloader进程中取消最新图片的加载
objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
给设置图片的UIImageView设置一个关联属性imageURLKey(可能是跟之后的缓存有关系),值为:Url
if (!(options & SDWebImageDelayPlaceholder)) { dispatch_main_async_safe(^{ self.image = placeholder; }); }
如果options参数不是SDWebImageDelayPlaceholder,就执行
dispatch_main_async_safe(^{ self.image = placeholder; });这里dispatch_main_async_safe是SDWebImage的宏定义:
主线程异步队列,然后去设置UIImage的image为占位符图
接下来这里对url进行一个判断
if (url) { ··· }
当Url等于nil
dispatch_main_async_safe(^{ [self removeActivityIndicator]; if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; completedBlock(nil, error, SDImageCacheTypeNone, url); } });
将一个UIActivityIndicatorView从UIImage中移除,当完成加载图片的闭包不是空的时候,生成一个错误类型,修改completedBlock的参数
当Url不等于nil
if ([self showActivityIndicatorView]) { [self addActivityIndicator]; }
[self showActivityIndicatorView]获取UIImage的关联属性UIActivityIndicatorView,如果没有关联过,返回false
[self addActivityIndicator];给关联属性
UIActivityIndicatorView初始化(如果初始化了就不初始化了)并设置属性
__weak __typeof(self)wself = self;
typeof(self) 是获取到self的类型,这样定义出的wself就是和self一个类型的, 加上weak是建立一个弱引用,整句就是给self定义了一个若
引用性质的替身;
这个一般用在使用
block时会用到,因为block会copy它内部的变量,可能会造成引用循环,使用weak性质的self替代self,可以切断block对self的引用,避免循环引用
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { }];
这里调用
SDWebImageManager去下载url的图片(这个之后会详细讲下)
[wself removeActivityIndicator];
在闭包里面用UIImage的引用,去remove UIImage中的
UIActivityIndicatorView
if (!wself) return;
如果wself等于nil就退出闭包了(可能是因为在闭包中,不知道之前的UIImage是否还在,所以我们需要判断下)
dispatch_main_sync_safe(^{ if (!wself) return; if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) { completedBlock(image, error, cacheType, url); return; } else if (image) { wself.image = image; [wself setNeedsLayout]; } else { if ((options & SDWebImageDelayPlaceholder)) { wself.image = placeholder; [wself setNeedsLayout]; } } if (completedBlock && finished) { completedBlock(image, error, cacheType, url); } });
这里在主线程同步队列执行:再次对wself进行判断
如果Image不为nil、completeBolck不为nil同时options等于SDWebImageAvoidAutoSetImage 执行
completedBlock(image, error, cacheType, url);
如果Image不为nil、但是completeBolck为nil或者options不等于 SDWebImageAvoidAutoSetImage,说明图片已经加载完毕了,最UIImage的image进行赋值
wself.image = image;然后执行
[wself setNeedsLayout];更新布局
当Image为nil或者completeBolck为nil同时options等于SDWebImageAvoidAutoSetImage,说明此时图片没有加载完毕,执行
wself.image = placeholder;
最后,如果completeBolck不为nil并且finished为True(加载完毕?)更新completeBolck
[self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];
根据
UIImageViewImageLoad取消Operation,然后获取UIView的关联属性loadOperationKey,然后再给这个属性设置一个operation操作,关键词还是
UIImageViewImageLoad
简而言之,UIImageView+WebCache
是给UIImageView的Image属性关联了一个设置图片的方法,并且通过SDWebImageManager
去下载图片,并刷新UIImageView的Image
@Blog
相关文章推荐
- Kruskal based on Greedy Algorithm
- C#静态方法在多用户并发访问时,运行情况到底是什么样?是排队等待?还是并发的?
- 【感悟】2015-2016年之Java培训有感
- ASP.NET弹出式日历选择控件的实现
- 在ASP.NET中怎么获取动态文本框的值(在程序的后台获取)
- java程序与操作系统API的关系
- Spring和SpringMVC的区别
- struct spring hibernate辨析
- Java权限访问修饰符 亲测总结
- c#面向对象基础3
- c#面向对象基础3
- ASP.NET刷新页面的六种方法
- C#.NET中GridView单行编辑的简单例子
- JAVA源码走读(一) HashMap与ArrayList
- java集合框架系列---ArrayList
- ASP.NET和ASP.NET MVC比较
- Matlab中fminunc函数的意义 以及options函数的初级用法。
- ASP.NET 怎么防止并发操作?
- 解决sublime使用pylint插件时对django的支持问题
- Quartz与Spring集成 Job如何自动注入Spring容器托管的对象