SDWebImage源码解析---疑难问题解答

2024-04-02 14:36

本文主要是介绍SDWebImage源码解析---疑难问题解答,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

SDWebImage的简单流程图:

在这里插入图片描述

上图大致流程是对的,有几个没写到的地方:

  1. 加载沙盒中对应的图片后,不仅要显示,而且要把图片缓存到内存中
  2. 下载完毕后,有一个异步解码的过程,没体现出来

网上有大佬做了这个图,供参考:
在这里插入图片描述
图片来源:SDWebImage源码解析(一)

源码看了一遍,写的很好,具体源码分析就不写了,后面会列出一些写的源码不错的文章。
这篇文章主要来解决两个问题:

问题一:

tableView多个cell同时请求,cell图片下载后显示错位问题

在tableView下,假设20个cell,每个cell都有图片下载操作,然后在下载的同时,下滑、上拉tableView,SDWebImage怎样确保下载的图片不会错位?

假如,tableView的cell没有重用机制,那么每个cell上的图片都是单独请求,即使上拉、下滑,cell的图片依然存在,并且图片下载完毕后,调用回调,将正确显示到imageView上

会出现错位的原因,是因为:某个cell1,已经不在屏幕上(虽然不在屏幕上,但是下载操作还在进行),放在了缓存池,被赋值了新的cell8,cell8有自己的url下载操作,这时,可能会将cell1下载的图片显示到cell8上。然后cell8的图片下载完后,再重新覆盖cell8

cell1与cell8是同一个对象,只是里面的属性值不一样

SDWebImage的处理方法是:
只要调用sd_setImageWithURL方法,则取消之前的所有下载操作
[self sd_cancelImageLoadOperationWithKey:validOperationKey];

self,就是调用下载图片的view,比如cell8上的UIImageView,每个cell上的UIImageView不同,因此,不需要担起其他cell上的UIImageView
虽然validOperationKey的值是NSStringFromClass([self class],也就是UIImageView
但是,调用者对象cell上的UIImageView,每个cell上都不一样,因此,不需要担心key一样的问题

这样,就确保cell8下载图片的时候,cell1的下载图片操作被停止,当cell8下载完毕后,显示的是cell8的图片

问题二:

多个同一个url请求,如何确保回调到正确的位置?

在一个tableView上,有20个cell都是请求同一个图片地址,且图片比较大,耗时20ms
此时,cell1去请求下载操作,处于正在下载中
而cell2去请求下载,发现已经有cell下载了,那么,cell1上的图片下载完毕后,如何让cell2知道下载完毕并显示呢?

SDWebImage库的设计考虑到了这样的情况,它可以很好地处理这种多个cell需要请求同一个URL的图片的情况。

SDWebImage底层通过使用一个NSOperationQueue来控制图片下载任务。当一个UIImage对象调用sd_setImageWithURL:方法时,SDWebImage会先在内存缓存中查找相应的图片,如果找不到,则在NSOperationQueue中增加一个新的下载操作。

由于SDWebImage内部使用了一个以URL为key的下载操作字典,对于相同URL的请求,它们其实只创建了一个下载操作,==其他的cell都会加入到这个下载操作的完成回调列表中。==即,把这个新请求的完成处理回调添加到已有下载操作的回调列表中。

所以当cell1上的图片下载完成后,cell2会通过回调知道图片已经下载完毕,并更新图片显示。

在 SDWebImage 的实现中,每个下载操作都会关联一个回调块(completion block)。当图片下载完成后,SDWebImage 会调用这个回调块,并将下载好的图片传递给回调块。在回调块中,SDWebImage 会遍历所有需要该图片的 cell,并调用它们的 sd_setImageWithURL:placeholderImage:options: 方法来更新图片显示。

下面是一个简化的示例代码,展示了 SDWebImage 的内部实现逻辑:

// SDWebImage 内部实现
- (void)downloadImageForURL:(NSURL *)url completion:(void (^)(UIImage *image))completion {// 检查内存缓存和磁盘缓存UIImage *cachedImage = [self.imageCache imageFromCacheForKey:url.absoluteString];if (cachedImage) {// 如果缓存中有图片,直接调用回调块并返回completion(cachedImage);return;}// 检查是否已经有下载操作正在进行中if ([self.downloadOperationDictionary objectForKey:url.absoluteString]) {// 如果已经有下载操作,将回调块添加到回调队列中[self.callbackDictionary[url.absoluteString] addObject:completion];return;}// 创建新的下载操作SDWebImageDownloaderOperation *operation = [SDWebImageDownloaderOperation new];[self.downloadOperationDictionary setObject:operation forKey:url.absoluteString];[self.callbackDictionary setObject:@[completion] forKey:url.absoluteString];// 开始下载图片[operation startWithURL:url completion:^(UIImage *image) {// 图片下载完成后的回调[self.imageCache storeImage:image forKey:url.absoluteString];// 调用所有关联的回调块for (void (^callback)(UIImage *) in self.callbackDictionary[url.absoluteString]) {callback(image);}// 清理下载操作和回调队列[self.downloadOperationDictionary removeObjectForKey:url.absoluteString];[self.callbackDictionary removeObjectForKey:url.absoluteString];}];
}

在上述代码中,当 cell1 请求下载图片时,SDWebImage 会创建一个新的下载操作,并将 cell1 的回调块添加到回调队列中。当 cell2 请求下载同一张图片时,SDWebImage 会发现已经有一个下载操作正在进行中,因此将 cell2 的回调块也添加到回调队列中。

当图片下载完成后,SDWebImage 会调用回调队列中的所有回调块,将下载好的图片传递给它们。这样,无论是 cell1 还是 cell2,都会在图片下载完成后收到通知并更新图片显示。

通过这种方式,SDWebImage 可以自动处理多个 cell 请求同一张图片的情况,避免重复下载,并确保所有需要该图片的 cell 都能及时更新显示。

源码论证:
在这里插入图片描述
如果operation已经存在,则shouldNotReuseOperation = NO
shouldNotReuseOperation = NO的话,直接走:
在这里插入图片描述
在这里插入图片描述
如果已经有下载操作,将回调块添加到回调队列中

在这里插入图片描述
图片下载完毕后,遍历tokens,取出里面的token,然后执行token的complete方法


SDWebImageView源码解析资料:

  1. SDWebImage源码解读之SDWebImageDownloader是一个系列文章,写的不错
  2. SDWebImage面试常问点知识点
  3. [iOS 开发] SDWebImage 源码阅读笔记
  4. 通读SDWebImage①–总体梳理、下载和缓存
  5. SDWebImage 源码解析–总览
  6. iOS-三方库-SDWebImage
  7. iOS SDWebImage 学习
  8. iOS复习中有关SDWebImage可能知识点总结(1)
  9. iOS开发之SDWebImage原理
  10. 源码,最主要的

这篇关于SDWebImage源码解析---疑难问题解答的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/870236

相关文章

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

Spring MVC使用视图解析的问题解读

《SpringMVC使用视图解析的问题解读》:本文主要介绍SpringMVC使用视图解析的问题解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring MVC使用视图解析1. 会使用视图解析的情况2. 不会使用视图解析的情况总结Spring MVC使用视图

利用Python和C++解析gltf文件的示例详解

《利用Python和C++解析gltf文件的示例详解》gltf,全称是GLTransmissionFormat,是一种开放的3D文件格式,Python和C++是两个非常强大的工具,下面我们就来看看如何... 目录什么是gltf文件选择语言的原因安装必要的库解析gltf文件的步骤1. 读取gltf文件2. 提