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

SDWebImage的简单流程图:

在这里插入图片描述

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

  1. 首先判断url的类型是不是URL类型或string类型,判断url是否为nil
  2. 占位图更早一些,在url判断后,就行显示占位图
  3. 加载沙盒中对应的图片后,不仅要显示,而且要把图片缓存到内存中
  4. 下载完毕后,有一个异步解码的过程,没体现出来
  5. 如果url正在下载中,则将这个url的下载回调加入到回调数组里面,当相同url下载完毕后,遍历数组,执行所有下载回调完成操作

网上有大佬做了这个图,供参考:
在这里插入图片描述
图片来源: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的话,直接走:
在这里插入图片描述
在这里插入图片描述
如果已经有下载操作,将回调块添加到回调队列中
@property (strong, nonatomic, nonnull) NSMutableArray<SDWebImageDownloaderOperationToken *> *callbackTokens;
callbackTokens是一个数组,里面保存着下载回调

在这里插入图片描述
图片下载完毕后,遍历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. 源码,最主要的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值