SDWebImage如何避免复用
写在最前面
大家都很忙, 如果你没时间看下面一长串的文字, 这里我尽量长话短说, 希望能节约一些你的时间
前提知识
1 每一个UIView+WebCache
都有一个operationDictionary 里面装的是 @{你当前的类名 : Operation}.
2 Operation直接影响图片能否被显示.每次有新的加载任务时都会检查这个字典, key相同则移除Operation, 再添加新的Operation, 下载完成后会移除Operation.
下面以tableViewcell 为例
1 tableViewCell第一次出现,以UIImageView为例 operationDictionary里装的是 @{@”UIImageView” : 第一张图的Operation}
2 这时候tableView上下滑动, cell复用, UIImageView去加载第二张图片(这就开始复用了),
3 这时候检查operationDictionary, 如果第一张图片还没有完成回调, key一定还存在operationDictionary中. 如果key重复了, 则移除第一张图的Operation, 并添加第二张图的Operation 即@{@”UIImageView” : 第二张图的Operation}.
4 候第一张图片下载完成, 准备回调时, 发现第一张图的Operation已经没有了, 就不会回调.
5 第二张图下载完成后, 会检查第二张图片的Operation有没有被第三张, 第四张…..移除.
6 如果图片对应的Operation存在 就调用回调方法,显示图片, 否则不调用回调, 也就不会显示.
由此 SDWebImage 就做到了 避免复用.
注意点
1. 我说的第一张图片,第二张图片,指的是同一个UIImageView要复用的图片, 不是tableView 上显示的第一张,第二张图片.
2. UIView+WebCache
是一个分类, 每一个对象都有自己的 operationDictionary.
当然如果你想具体了解, 可以往下看.
前言:
SDWebImage是iOS开发最常见的开源框架之一, 对SDWebImage的讲解网上非常多, 我在这里就不放传送门了。 在tableView上使用SDWebImage加载图片时能很好的避免复用问题, 那么他是怎么做到的呢? 自己研究了一下, 下面与大家分享。
前提
在看下面之前, 我认为大家已经看过SDWebimage源码, 这里只会对避免复用这块逻辑讲解, 不对其他逻辑做太多解释。 如果看官还没有看过源码, 建议先上网搜下详解, 以免一会有不适感。
正文
- 第一个问题, tableViewCell 上下滚动, ImageView被复用了但是之前加载的图片没有显示出来, 说明了什么?
对的, 说明之前的操作被取消了对吗? 那么怎么被取消的呢? 第一反应就是回调的block被终止了, 对吗? 我跟了一下源码发现取消操作是在SDWebImageManager
里取消的. 请看下图.
经过我的打印发现, if (!strongOperation || strongOperation.isCancelled)
这个判断能进去的原因是strongOperation
是nil
2. 那么下一个问题strongOperation
在什么时候被置空的?
如果知道了这个问题, 那么为什么imageView复用为什么不会显示错误的图片的问题 我们就弄清楚了.
先看下图
简单说下 UIView+WebCache 调用 SDWebImageManager的方法, 在SDWebImageManager方法里 创建OPeration. Operation去了两个地方, 1. 返回给了 UIView+WebCache. 2. 被抓取到 SDWebImageManager方法内部的Block里了(也就是刚才看到的 取消操作的地方).
好的下面我们看看 UIView+WebCache.
里做了什么 会让strongOperation
置nil.
2 UIView+WebCache
请看下图
关注一下 划线的两个方法
先讲第二个那个方法
[self sd_setImageLoadOperation:operation forKey:validOperationKey];
这个方法的调用,则是把strongOperation
添加到字典里的方法.
查看源码我们可以看到
- (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key {if (key) {// 取消已经存在的key, Operation// 重新加入到 Operation字典中[self sd_cancelImageLoadOperationWithKey:key];if (operation) {SDOperationsDictionary *operationDictionary = [self operationDictionary];operationDictionary[key] = operation;}}
}
将operation 添加到operationDictionary字典中
再说第一个那个划线的方法.
// 如果Operation 字典里 有这个 Operation 则取消 说明这个view 有新的下载任务了.[self sd_cancelImageLoadOperationWithKey:validOperationKey];
这个方法的调用就是我们要找的把strongOperation
置nil的地方. 每次有图片需要加载的时候, 都会走这里, 这个方法会检查根据key能不能取到值,如果能取到, 这将这个 Operation 调用取消方法, 且将他中字典里移除.
查看源码
- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key {// Cancel in progress downloader from queue// 如果有 当前key 有所对应的 Operation. 则将Operation 取消.并且将key -value 从 OperationDictiona中移除.SDOperationsDictionary *operationDictionary = [self operationDictionary];id operations = operationDictionary[key];if (operations) {if ([operations isKindOfClass:[NSArray class]]) {for (id <SDWebImageOperation> operation in operations) {if (operation) {[operation cancel];}}} else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){ // 检查 代理是否 被实现.[(id<SDWebImageOperation>) operations cancel];}[operationDictionary removeObjectForKey:key]; }else{}
}
这段代码其实就是, 在operationDictionary里根据key查找, 如果有则取消, 并且从operationDictionary里面移除.也是导致 strongOperation
是nil的直接原因.
好了, 这就是strongOperation
被置成nil的原因
下面我们关注 这个字典里的key, 因为 strongOperation
是根据key找到到.
4 key
我们先来看下 key是怎么创建的
NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]);[self sd_cancelImageLoadOperationWithKey:validOperationKey];
如果我们使用myimageView sd_setImageWithUR:xxxx
这种方式 operationKey是nil, 那么 key 是通过NSStringFromClass([self class])
创建的.以UIImageView为例 key 就是 @”UIImageView”.
让我们串起来讲一下
每次有新的加载任务会做两件事
1 检查operationDictionary有没有相同的key 有则将key对应的Operation 取消并删除,
2 将新任务的Operation添加到字典中. 加载图片完成后, 回调时会先检查任务的Operation还在不在, 不在了 则不回调显示, 反之回调显示并移除Operation.
好了, 这就是我理解的SDWebImage 避免复用的方法.
注意点 1. UIView+WebCache是一个分类, 每一个UIImageView都有一个operationDictionary 这里面key发生重复的原因只有一个,就是这个容器上一个加载任务还没完成, 新的加载任务又开始了.这是我一开始没转过弯 理解上卡主的地方.
SDWebImage如何避免复用相关推荐
- 【iOS开发】—— SDWebImage源码学习(未完)
文章目录 什么是SDWebImage? sd_setImageWithURL调用关系 步骤一 步骤三 步骤四 步骤五 步骤六 下载步骤 UIImageView+ WebCache UIView+ We ...
- 【iOS】SDWebImage
文章目录 SDWebImage 日常使用 一些主要功能 获取图片缓存 缓存机制 独立的异步图像下载 独立的异步图像缓存 图片加载全过程 源码分析 架构图 结构 SDWebImageManager 1. ...
- UI一揽子计划 21 (UICollectionView、SDWebImage第三方类库加载图片的使用、集合视图的布局UICollectionViewFlowLayout 、自定义Cell、布局协议
Pro : SDWebImage第三方类库加载图片的使用: 1.在MRC 环境下 使用ARC 的类库: -fobjc-arc (Build Phases --> Compile Sourc ...
- 2022-2028年中国密集型光波复用(DWDM)设备行业市场前瞻与投资战略规划分析报告
[报告类型]产业研究 [报告价格]¥4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了中国密集型光波复用(DWDM)设备行业市场 ...
- [导入]C#中实现Socket端口复用
一.什么是端口复用: 因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分.这种多重绑定便称之为端口 ...
- 基于Charlieplexing算法(查理复用算法)的LED矩阵控制设计
目录 1.Charlieplexing 基本原理 2.Charlieplexing 注意事项 3.结论 最近发现一个非常有意思的实验:查理复用技术控制LED灯(按键). 简单来说就是:希望能够用较少的 ...
- Go 分布式学习利器(16) -- go中可复用的package构建
通过本文,你将了解go 语言中如何将自己的package构建到项目中 以及如何将远程(github)的package构建到项目中. 1. 构建本地的package package 是可复用模块的基本单 ...
- Go 分布式学习利器(12)-- Go语言的扩展和复用
Go语言无法天然支持继承,但是又想要实现面向对象的特性. 即父类对象 使用子类对象初始化,那么该父类对象调用的函数就是子类实现的函数 ,从而满足LSP(子类交换原则). 案例一: Go语言 支持扩展父 ...
- SDWebImage使用——一个可管理远程图片加载的类库
SDWebImage托管在github上.https://github.com/rs/SDWebImage 这个类库提供一个UIImageView类别以支持加载来自网络的远程图片.具有缓存管理.异步下 ...
最新文章
- STL erase() 迭代器失效
- 实现不同vlan间PC不可互访,而不同vlan的PC均可访问服务器的特殊效果,(华为)...
- idea启动多个tomcat失败
- mysql+firewall_mysql - ERROR 1123(HY000):无法初始化函数'mysql_firewall'; 插件初始化功能失败 - 堆栈内存溢出...
- Hadoop、storm和Spark的区别、比较
- pythonjam教程_Python学习:安装配置pycharm编辑器教程
- HDU4681 String(dp)
- HDOJ 2071 Max Num
- 新版掌上阅读小说源码+支持公众号/分站/封装APP
- 东芝打印机共享怎么设置_东芝2051C打印机怎么连接并扫描文件到电脑?
- matlab画空间分布图,matlab空间图形的画法.doc
- Python——利用协程实现视频的拖影效果
- 【C#上位机】西门子1200PLC实用定位控制程序案例
- html中输入框中“请输入关键字”的设置
- Opencv图片锐化
- MFormats SDK智能视频 API,视频软件开发框架
- IE10和IE9兼容性常见问题解答(FAQ)
- 漫谈程序员系列:咦,你也在混日子啊
- 计算机前沿知识论文,计算机前沿技术论文.pdf
- 手机号/邮箱/身份证验证