写在最前面

大家都很忙, 如果你没时间看下面一长串的文字, 这里我尽量长话短说, 希望能节约一些你的时间

前提知识
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源码, 这里只会对避免复用这块逻辑讲解, 不对其他逻辑做太多解释。 如果看官还没有看过源码, 建议先上网搜下详解, 以免一会有不适感。


正文

  1. 第一个问题, 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如何避免复用相关推荐

  1. 【iOS开发】—— SDWebImage源码学习(未完)

    文章目录 什么是SDWebImage? sd_setImageWithURL调用关系 步骤一 步骤三 步骤四 步骤五 步骤六 下载步骤 UIImageView+ WebCache UIView+ We ...

  2. 【iOS】SDWebImage

    文章目录 SDWebImage 日常使用 一些主要功能 获取图片缓存 缓存机制 独立的异步图像下载 独立的异步图像缓存 图片加载全过程 源码分析 架构图 结构 SDWebImageManager 1. ...

  3. UI一揽子计划 21 (UICollectionView、SDWebImage第三方类库加载图片的使用、集合视图的布局UICollectionViewFlowLayout 、自定义Cell、布局协议

    Pro : SDWebImage第三方类库加载图片的使用: 1.在MRC 环境下 使用ARC 的类库: -fobjc-arc   (Build Phases  --> Compile Sourc ...

  4. 2022-2028年中国密集型光波复用(DWDM)设备行业市场前瞻与投资战略规划分析报告

    [报告类型]产业研究 [报告价格]¥4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了中国密集型光波复用(DWDM)设备行业市场 ...

  5. [导入]C#中实现Socket端口复用

    一.什么是端口复用: 因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分.这种多重绑定便称之为端口 ...

  6. 基于Charlieplexing算法(查理复用算法)的LED矩阵控制设计

    目录 1.Charlieplexing 基本原理 2.Charlieplexing 注意事项 3.结论 最近发现一个非常有意思的实验:查理复用技术控制LED灯(按键). 简单来说就是:希望能够用较少的 ...

  7. Go 分布式学习利器(16) -- go中可复用的package构建

    通过本文,你将了解go 语言中如何将自己的package构建到项目中 以及如何将远程(github)的package构建到项目中. 1. 构建本地的package package 是可复用模块的基本单 ...

  8. Go 分布式学习利器(12)-- Go语言的扩展和复用

    Go语言无法天然支持继承,但是又想要实现面向对象的特性. 即父类对象 使用子类对象初始化,那么该父类对象调用的函数就是子类实现的函数 ,从而满足LSP(子类交换原则). 案例一: Go语言 支持扩展父 ...

  9. SDWebImage使用——一个可管理远程图片加载的类库

    SDWebImage托管在github上.https://github.com/rs/SDWebImage 这个类库提供一个UIImageView类别以支持加载来自网络的远程图片.具有缓存管理.异步下 ...

最新文章

  1. STL erase() 迭代器失效
  2. 实现不同vlan间PC不可互访,而不同vlan的PC均可访问服务器的特殊效果,(华为)...
  3. idea启动多个tomcat失败
  4. mysql+firewall_mysql - ERROR 1123(HY000):无法初始化函数'mysql_firewall'; 插件初始化功能失败 - 堆栈内存溢出...
  5. Hadoop、storm和Spark的区别、比较
  6. pythonjam教程_Python学习:安装配置pycharm编辑器教程
  7. HDU4681 String(dp)
  8. HDOJ 2071 Max Num
  9. 新版掌上阅读小说源码+支持公众号/分站/封装APP
  10. 东芝打印机共享怎么设置_东芝2051C打印机怎么连接并扫描文件到电脑?
  11. matlab画空间分布图,matlab空间图形的画法.doc
  12. Python——利用协程实现视频的拖影效果
  13. 【C#上位机】西门子1200PLC实用定位控制程序案例
  14. html中输入框中“请输入关键字”的设置
  15. Opencv图片锐化
  16. MFormats SDK智能视频 API,视频软件开发框架
  17. IE10和IE9兼容性常见问题解答(FAQ)
  18. 漫谈程序员系列:咦,你也在混日子啊
  19. 计算机前沿知识论文,计算机前沿技术论文.pdf
  20. 手机号/邮箱/身份证验证

热门文章

  1. 数字资产普及,如何规避加密风险?
  2. 教你如何全面认识磁盘阵列柜
  3. linux内核熵池,快速的给内核熵池喂随机数
  4. ROS2 基础概念 参数
  5. 数电和Verilog-基础概念
  6. 趣味算法 四个点在同一个半圆的概率
  7. 电驴emule v0.50a安装与设置
  8. 我的markdown编辑器
  9. matlab:图像处理
  10. 7 线性布局——LinearLayout