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

相关文章

python常见环境管理工具超全解析

《python常见环境管理工具超全解析》在Python开发中,管理多个项目及其依赖项通常是一个挑战,下面:本文主要介绍python常见环境管理工具的相关资料,文中通过代码介绍的非常详细,需要的朋友... 目录1. conda2. pip3. uvuv 工具自动创建和管理环境的特点4. setup.py5.

全面解析HTML5中Checkbox标签

《全面解析HTML5中Checkbox标签》Checkbox是HTML5中非常重要的表单元素之一,通过合理使用其属性和样式自定义方法,可以为用户提供丰富多样的交互体验,这篇文章给大家介绍HTML5中C... 在html5中,Checkbox(复选框)是一种常用的表单元素,允许用户在一组选项中选择多个项目。本

Python包管理工具核心指令uvx举例详细解析

《Python包管理工具核心指令uvx举例详细解析》:本文主要介绍Python包管理工具核心指令uvx的相关资料,uvx是uv工具链中用于临时运行Python命令行工具的高效执行器,依托Rust实... 目录一、uvx 的定位与核心功能二、uvx 的典型应用场景三、uvx 与传统工具对比四、uvx 的技术实

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析

《Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析》InstantiationAwareBeanPostProcessor是Spring... 目录一、什么是InstantiationAwareBeanPostProcessor?二、核心方法解

深入解析 Java Future 类及代码示例

《深入解析JavaFuture类及代码示例》JavaFuture是java.util.concurrent包中用于表示异步计算结果的核心接口,下面给大家介绍JavaFuture类及实例代码,感兴... 目录一、Future 类概述二、核心工作机制代码示例执行流程2. 状态机模型3. 核心方法解析行为总结:三

springboot项目中使用JOSN解析库的方法

《springboot项目中使用JOSN解析库的方法》JSON,全程是JavaScriptObjectNotation,是一种轻量级的数据交换格式,本文给大家介绍springboot项目中使用JOSN... 目录一、jsON解析简介二、Spring Boot项目中使用JSON解析1、pom.XML文件引入依

Python中文件读取操作漏洞深度解析与防护指南

《Python中文件读取操作漏洞深度解析与防护指南》在Web应用开发中,文件操作是最基础也最危险的功能之一,这篇文章将全面剖析Python环境中常见的文件读取漏洞类型,成因及防护方案,感兴趣的小伙伴可... 目录引言一、静态资源处理中的路径穿越漏洞1.1 典型漏洞场景1.2 os.path.join()的陷