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

news2024/11/26 11:38:09

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JAVASE】学习数组的定义与使用

✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉 🍎个人主页: 再无B~U~G-CSDN博客 目标: 1. 理解数组基本概念 2. 掌握数组的基本用法…

腾讯云函数计算技术:云原生架构下的Serverless与微服务新篇章

作者:哈哥撩编程(视频号、公众号、抖音同名) 新星计划全栈领域优秀创作者博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者 文章目录 前言全面上云之首战:春保&#…

探索DAPP生态:代币预售、系统开发、NFT质押分红和代币质押技术

随着区块链技术的迅速发展,去中心化应用程序(DAPPs)生态系统已经成为了数字经济的一部分,并在不断壮大和发展。DAPP生态系统的繁荣离不开代币预售、系统开发、NFT质押分红和代币质押技术等关键要素的支持和推动。本文将深入探讨这…

热门IT【视频教程】-华为/思科/红帽/oracle

华为认证 网络工程师-入门基础课:华为HCIA认证课程介绍-CSDN博客 网络工程师进阶课:华为HCIP认证课程介绍-CSDN博客 职场进阶,踏上高峰——HCIE-Datacom认证-CSDN博客 华为HCIA试听课程 : 超级实用,华为VRP系统文件…

算法——距离计算

距离计算常用的算法包括欧氏距离、曼哈顿距离、切比雪夫距离、闵可夫斯基距离、余弦相似度等。这些算法在数据挖掘、机器学习和模式识别等领域中被广泛应用。 1.欧氏距离 欧式距离也称欧几里得距离,是最常见的距离度量,衡量的是多维空间中两个点之间的…

【LeetCode】三月题解

文章目录 [2369. 检查数组是否存在有效划分](https://leetcode.cn/problems/check-if-there-is-a-valid-partition-for-the-array/)思路:代码: [1976. 到达目的地的方案数](https://leetcode.cn/problems/number-of-ways-to-arrive-at-destination/) 思路…

lua脚本在redis集群中哈希槽分片问题

上文说到,通过用redis lua脚本实现时间窗分布式限流 可以操作redis lua脚本来实现时间窗限流,在执行lua脚本的时候,参数中有个keys列表,当lua脚本中如果有操作多个key的情况,就可以传个key列表了。通常情况下&#xff…

[蓝桥杯 2019 省赛 AB] 完全二叉树的权值

# [蓝桥杯 2019 省 AB] 完全二叉树的权值 ## 题目描述 给定一棵包含 $N$ 个节点的完全二叉树,树上每个节点都有一个权值,按从上到下、从左到右的顺序依次是 $A_1,A_2, \cdots A_N$,如下图所示: 现在小明要把相同深度的节点的权值…

【Windows】windows的bat命令获取当前文件名称

新建.txt文本输入IR *.* /B >LIST.TXT LIST.TXT 提取到LIST.TXT文件 重命名txt文本后缀为.bat双击.bat文件 DIR *.* /B >LIST.TXT效果图

git学习——tags、release、drop commit

最近一直都在持续学习git相关内容,越来越发现git是一个十分适合大型项目和团队协作进行开发的工具,掌握好了对于我们参与项目维护和开发产品帮助很大,所以要不断持续学习git。 tags & releases tag的创建 当我们在git版本控制中遇到了…

57、FreeRTOS/串口通信和DMA ADC PWM相关20240401

一、使用PWMADC光敏电阻完成光控灯的实验。(根据测得的光敏电阻大小,控制灯的亮度) 代码: /* USER CODE BEGIN 2 */HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);//打开定时器的PWM通道3HAL_TIM_PWM_Start(&htim3,TIM_CHANN…

学习笔记——C语言基本概念指针(下)——(8)

1.指针和数组 数组指针 -- 指向数组的指针。 指针数组 -- 数组的元素都是指针。 换句话理解就是:数组指针就是个指针,指针数组就是个数组。 1.1数组指针 数组指针:指向数组的指针; 先回顾一下数组的特点: 1.相…

Linux权限提升总结

几个信息收集的项目推荐 运行这几个项目就会在目标主机上收集一些敏感信息供我们参考和使用 一个综合探针:traitor 一个自动化提权:BeRoot(gtfo3bins&lolbas) 使用python2运行beroot.py就可以运行程序,然后就可以收集到系统中的大量信…

Hive详解(5)

Hive 窗口函数 案例 需求:连续三天登陆的用户数据 步骤: -- 建表 create table logins (username string,log_date string ) row format delimited fields terminated by ; -- 加载数据 load data local inpath /opt/hive_data/login into table log…

【Java】反射简介,利用反射打印一个类当中的构造函数,方法和属性。

📝个人主页:哈__ 期待您的关注 我想要通过反射来打印如下效果的类信息。 Student类如下代码所示。 package com.my.reflect;public class Student {public String name;public int age;public Student(){}public Student(String name, int age) {this…

探索组合总和问题(力扣39,40,216)

文章目录 题目前知LinkedList和ArryayList 组合总和I一、思路二、解题方法三、Code 组合总和II一、思路二、解题方法三、Code 组合总和III一、思路二、解题方法三、Code 总结 先看完上一期组合问题再看这一期更加容易理解喔🤯 在算法和编程的世界中,组合…

走向国际:区块链行业项目海外市场宣传与运营攻略

随着区块链技术的不断发展和应用,越来越多的区块链项目开始将目光投向海外市场。在全球范围内寻找用户和投资者,扩大品牌知名度,是许多区块链项目的共同目标。然而,要成功进军海外市场,并不是一件容易的事情。本文将深…

Vscode运行python

按住 xtrlshiftp,会出现下面的界面: 然后选择第一个选项,会出现如下的界面: 选择某个环境后就可以使用了。可以右键,如下所示: 就可以运行python程序了

如何在Ubuntu系统部署Z-blog博客结合cpolar实现无公网IP访问本地网站

文章目录 1. 前言2. Z-blog网站搭建2.1 XAMPP环境设置2.2 Z-blog安装2.3 Z-blog网页测试2.4 Cpolar安装和注册 3. 本地网页发布3.1. Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 想要成为一个合格的技术宅或程序员,自己搭建网站制作网页是绕…

基于WEB的花卉养殖知识平台

基于WEB的花卉养殖知识平台的设计与实现 摘要 随着人们生活水平及生活质量要求的日益提升,花卉也成为了人们日常生活的调味剂,同时对于花卉的养殖及养护不再是老年人的专利,很多年轻人也在通过花卉的养护来舒缓工作压力,同时通过…