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. 源码,最主要的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/509289.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

修改nuxtjs项目中的浏览器图标步骤

处理步骤: 打开配置页面 使用el-upload 上传图片到后台 后台把图片转为ico,返回图标路径 配置页面修改本页面预览图,点击保存,修改的数据库。 通知nuxt布局页面,修改head节点中的图标属性,…

智慧酒店(二):AI智能分析网关V4视频分析技术在酒店管理中的应用

一、人工智能技术如何应用在酒店管理中? 随着科技的飞速发展,人工智能技术已经逐渐渗透到我们生活的方方面面,其中,酒店管理行业便是其应用的重要领域之一。人工智能技术以其高效、精准的特点,为酒店管理带来了革命性…

基于java的智能停车场管理系统

开发语言:Java 框架:ssm 技术:JSP JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclip…

文件管理原理

文章目录 1)一个文件,它是文件内容和文件属性的集合 文件文件属性文件内容 文件属性 文件内容 2)文件分为打开的文件和未打开的文件 3)打开的文件是谁打开的? 由进程打开!而研究一个被打开的进程本质就是研究进程和文件的关系。 而被打开的…

vue快速入门(二)安装vue调试插件

教程很详细,直接上过程 上一篇 新增内容 在国内网站下载谷歌插件安装插件 点击跳转极简插件 此处我们以Chrome浏览器为例 到这里我们就成功安装了插件 使用上一篇博客的代码在浏览器F12调试一下 这样就可以使用了!!!

依赖倒转原则

1.1 MM请求电脑 MM电脑坏了,需要修电脑,是因为每次打开QQ,一玩游戏,机器就死了。出来蓝底白字的一堆莫名奇妙的英文。蓝屏死机了,估计内存有问题。 1.2 电话遥控修电脑 遥控修理电脑,打开内存条,两根内存…

Python学习从0到1 day20 第二阶段 面向对象 ② 封装

缘分 朝生暮死犹如露水 —— 24.4.1 学习目标: 1.理解封装的概念 2.掌握私有成员的使用 一、面向对象三大特性: 面向对象编程,是许多编程语言都支持的一种编程思想 简单理解是:基于模板(类)去创建实体&…

免费分享一套SpringBoot+Vue健身房管理系统,帅呆了~~

大家好,我是java1234_小锋老师,看到一个不错的SpringBootVue健身房管理系统,分享下哈。 项目视频演示 【免费】SpringBootVue健身房管理系统 Java毕业设计_哔哩哔哩_bilibili【免费】SpringBootVue健身房管理系统 Java毕业设计项目来自互联…

【SQL Server】2. 将数据导入导出到Excel表格当中

最开始,博主介绍一下自己的环境:SQL Sever 2008 R2 SQL Sever 大致都差不多 1. 通过自带软件的方式 首先找到下载SQL Sever中提供的导入导出工具 如果开始界面没有找到自己下载的路径 C:\Program Files\Microsoft SQL Server\100\DTS\Binn下的DTSWiz…

题目:小明的背包5(蓝桥OJ 1178)

问题描述&#xff1a; 解题思路&#xff1a; 分组背包模板题&#xff0c;与优化01背包的不同之处在于第一维不可省略&#xff0c;要写s循环。注意要初始化 #include <bits/stdc.h> using namespace std; const int N 1e3 9; int dp[N][N]; // 分组背包模板&#xff0c;…

正则表达式浅析

正则表达式&#xff0c;又称正规表示法、常规表示法&#xff08;英语&#xff1a;Regular Expression&#xff0c;在代码中常简写为regex、regexp或RE&#xff09;&#xff0c;计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很…

【详细教程制作】用户列表

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

什么是工业协议转换软件?

在现代工业自动化领域&#xff0c;随着技术的不断革新和智能化水平的提升&#xff0c;各种工业设备和系统之间的通信变得日益重要。然而&#xff0c;由于历史、技术差异和标准多样化等原因&#xff0c;不同的工业设备和系统往往采用各自独特的通信协议&#xff0c;导致它们之间…

短视频素材哪里找?6个短视频素材下载推荐

哈喽&#xff01;短视频制作的小艺术家们&#xff0c;是不是时常在探寻短视频素材哪里找的秘密&#xff1f;放下你的疑惑吧&#xff0c;我来带你揭开6个藏宝图&#xff0c;领你进入短视频素材的奇妙世界&#xff0c;让你的作品在抖音、快手等平台上大放异彩&#xff01; 蛙学网…

经典文献阅读之--als_ros(移动机器人的可靠蒙特卡罗定位)

0. 简介 在本文中&#xff0c;我们关注移动机器人定位的可靠性问题。蒙特卡罗定位&#xff08;MCL&#xff09;广泛用于移动机器人的定位。然而&#xff0c;由于缺乏判定MCL估计可靠性的方法&#xff0c;其安全性仍难以保证。本文提出了一种新型定位框架&#xff0c;能够同时实…

springcloud基本使用二(远程调用)

创建两个springboot maven子项目 子项目名称分别为order-server和user-server 配置user-server子项目: 所需依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependenc…

线程安全问题+读写者问题

⭐小白苦学IT的博客主页 ⭐初学者必看&#xff1a;Linux操作系统入门 ⭐代码仓库&#xff1a;Linux代码仓库 ❤关注我一起讨论和学习Linux系统 1.什么是线程安全问题&#xff1f; 线程安全问题是指在多线程环境中&#xff0c;当多个线程同时访问共享数据时&#xff0c;由于操作…

【RISC-V】如何使用release的risc-v gnu toolchain

riscv64-elf-ubuntu-22.04-gcc-nightly-2024.03.01-nightly.tar.gz 首先去release页面中获取相应的压缩包 将压缩包解压到想解压的位置&#xff0c;这里我选择了 mv Downloads/riscv64-elf-ubuntu-22.04-gcc-nightly-2024.03.01-nightly.tar.gz riscv64-tool-chain/然后解压…

Mac - Keychron K3 Pro 功能键改键 -via 改键配置 For Mac

前言 Keychron K3 Pro键盘连接Mac使用&#xff0c;顶部一排功能键&#xff0c;默认是Mac的多媒体功能键。F1&#xff5e;F12功能键&#xff0c;需要按&#xff1a;Fn F1&#xff5e;F12。 而在我的日常工作中&#xff0c;常用的是F1&#xff5e;F12&#xff0c;期望F1~F12功…

开源推荐榜【Pear Admin Flask 用python来创建后台管理系统】

最新技术高效快速开发&#xff0c;前后端分离模式&#xff0c;开箱即用。 核心模块包括&#xff1a;用户、角色、职位、组织机构、菜单、字典、日志、多应用管理、文件管理、定时任务等功能。 代码量少、学习简单、功能强大、轻量级、易扩展&#xff0c;轻松开发从现在开始&…