SDWebImage源代码阅读(一)

SDWebImage源代码阅读(一)

border="0" width="530" height="100" src="http://music.163.com/outchain/player?type=2&id=29947420&auto=1&height=66">
首先看了张朝龙的博客关于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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值