在 iOS 的图片加载框架中,SDWebImage 可谓是占据大半壁江山。它支持从网络中下载且缓存图片,只要一行代码就可以实现图片异步下载和缓存功能,并设置图片到对应的 UIImageView 控件或者 UIButton 控件。在项目中使用 SDWebImage 来管理图片加载相关操作可以极大地提高开发效率,让我们更加专注于业务逻辑实现
SDWebImage 概论
1.提供了一个 UIImageView 的 category 用来加载网络图片并且对网络图片的缓存进行管理
2.采用异步方式来下载网络图片
3.采用异步方式,使用 memory+disk 来缓存网络图片,自动管理缓存。
4.支持 GIF 动画
5.支持 WebP 格式
6.同一个 URL 的网络图片不会被重复下载
7.失效的 URL 不会被无限重试
8.耗时操作都在子线程,确保不会阻塞主线程
9.使用 GCD 和 ARC
10.支持 Arm64
SDWebImage 使用
1.使用 ImageView+WebCache category 来加载 UITableView 中 cell 的图片
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
2.使用 block,采用这个方案可以在网络图片加载过程中得知图片的下载进度和图片加载成功与否
[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 ...
}];
3.使用 SDWebImageManager,SDWebImageManager 为UIImageView+WebCache category 的实现提供接口。
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
}
}];
4.加载图片还有使用 SDWebImageDownloader 和 SDImageCache 方式,但那个并不是我们经常用到的。基本上面所讲的3个方法都能满足需求。
SDWebImage 流程
SDWebImage 接口
SDWebImage 是一个成熟而且比较庞大的框架,但是在使用过程中并不需要太多的接口,这算是一种代码封装程度的体现。这里就介绍比较常用的几个接口。
给 UIImageView 设置图片的接口,SDWebImage 有提供多个给UIImageView 设置图片的接口,最终所有的接口都会调用下图的这个接口,这是大多数框架的做法。
获取 SDWebImage 的磁盘缓存大小,在项目中有时候会需要统计应用的磁盘缓存内容大小,那么获取图片的缓存大小就是使用这个接口来实现
[SDImageCache sharedImageCache] getSize];
清理内存缓存,清理内存中缓存的图片资源,释放内存资源。
[[SDImageCache sharedImageCache] clearMemory];
有了清理内存缓存,自然也有清理磁盘缓存的接口
[[SDImageCache sharedImageCache] clearDisk];
SDWebImage 解析
解析主要围绕着 SDWebImage 的图片加载流程来分析,介绍SDWebImage 这个框架加载图片过程中的一些处理方法和设计思路。
1.给 UIImageView 设置图片,然后 SDWebImage 调用这个最终的图片加载方法。
2.开始加载之前图片先取消对应的 UIImageView 先前的图片下载操作。试想,如果我们给 UIImageView 设置了一张新的图片,那么我们还会在意该 UIImageVIew 先前是要加载哪一张图片么?应该是不在意的吧!那是不是应该尝试把该 UIImageView 先前的加载图片相关操作给取消掉呢?
[self sd_cancelCurrentImageLoad]
该方法经过周转,最后调用了以下方法,框架将图片对应的下载操作放到 UIView 的一个自定义字典属性 (operationDictionary) 中,取消下载操作第一步也是从这个 UIView 的自定义字典属性 (operationDictionary)中取出所有的下载操作,然后依次调用取消方法,最后将取消的操作从(operationDictionary) 字典属性中移除。
3.移除之前没用的图片下载操作之后就创建一个新的图片下载操作,然后设置到 UIView 的一个自定义字典属性 (operationDictionary) 中。
4.看看如何创建一个新的图片下载操作,框架保存了一个失效的 url 列表,如果 url 失效了就会被加入这个列表,保证不会重复多次请求失效的 url。
根据给定的 url 生成一个唯一的 key ,之后利用这个 key 到缓存中查找对应的图片缓存。
5.读取图片缓存,根据 key 先从内存中读取图片缓存,若没有命中内存缓存则读取磁盘缓存,如果磁盘缓存命中,那么将磁盘缓存读到内存中成为内存缓存。如果都没有命中缓存的话,那么就在执行的 doneBlock中开始下载图片。
6.图片下载操作完成后会将图片对应的数据通过 completedBlock 进行回调
在图片下载方法中,调用了一个方法用于添加创建和下载过程中的各类block 回调。
添加该 url 加载过程的状态回调 block
如果该 url 是第一次加载的话,那么就会执行 createCallback 这个回调block ,然后在 createCallback 里面开始构建网络请求,在下载过程中执行各类进度 block 回调。
7.当图片下载完成之后会回到 done 的 block 回调中做图片转换处理和缓存操作
回到 UIImageView 控件的设置图片方法 block 回调中,给对应的UIImageView 设置图片,操作流程到此完成。
8.304 的处理
SDWebImage在加载图片网络请求的 NSURLConnection 的代理中对httpCode 做了判断,当 httpCode 为 304 的时候放弃下载,读取缓存。
总结
SDWebImage 作为一个优秀的图片加载框架,提供的使用方法和接口对开发者来说非常友好。其内部实现多是采用 block 的方式来实现回调,代码阅读起来可能没有那么直观。此文章旨在给大家讲解 SDWebImage 这个框架的图片大概加载流程,其中具体细节限于篇幅无法详细深究.
参考:
- 注释项目
2.[iOS 开发] SDWebImage 源码阅读笔记
3.https://www.jianshu.com/p/0e49fa89a2d2
4.https://www.jianshu.com/p/52845e44163a
5.https://www.jianshu.com/p/bdf27a564fa4