【iOS】—— SDWebImage源码学习(1)(未完)

iOS】------ SDWebImage源码学习

SDWebImage

SDWebImage具有缓存支持的异步映像下载程序。并添加了像UI元素分类类UIImageView、UIButton、MKAnnotationView,可以直接为这些UI元素添加图片。

基础使用

在日常的使用中,通常是加载网络图片到UIImageView上展示,所以一般在需要使用SDWebImage的文件中只引用#import "UIImageView+WebCache.h"头文件。

最简单的加载方式是只加载图片地址:

objectivec 复制代码
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:imageView];
    
[imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]];

SDWebImage也提供了其他的加载方法,不过点击方法进入查看后,发现最终都是调用其全能方法:

objectivec 复制代码
- (void)sd_setImageWithURL:(nullable NSURL *)url {
    [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
}

全能方法除了必需的的图片地址,还提供了占位图、可选项、加载进度和完成回调。

objectivec 复制代码
- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                   options:(SDWebImageOptions)options
                  progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                 completed:(nullable SDExternalCompletionBlock)completedBlock;

占位图像: 在网络图片加载过程中,ImageView会显示占位图像,给用户一个视觉上的暂时反馈。当网络图片加载完成后,ImageView中会显示加载完成的图片。
选项: 是一个枚举类型的值,用于设置加载图片的选项。其中包含了一些常用的选项,例如缓存策略、图片解码方式、加载优先级等。通过传递不同的选项,可以对图片加载的行为进行定制。
进度: 它们提供了对图片加载过程中的进度和结果的反馈。它们提供了对图片加载过程中的进度和结果的反馈。
完成回调: 是一个块对象,用于在图片加载完成后执行相应的操作。

点击进入全能方法中:

objectivec 复制代码
- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                   options:(SDWebImageOptions)options
                  progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                 completed:(nullable SDExternalCompletionBlock)completedBlock {
    [self sd_internalSetImageWithURL:url
                    placeholderImage:placeholder
                             options:options
                        operationKey:nil
                       setImageBlock:nil
                            progress:progressBlock
                           completed:completedBlock];
}

全能方法并没有什么实际的实现,只是对另一个方法的封装。

主要功能

  1. 对UIImageView、UIButton、MKAnnotationView添加Web图像和告诉缓存管理。
  2. 异步图像下载器。
  3. 具有自动缓存到期处理的异步内存+磁盘映像缓存。
  4. 背景图像解压缩。
  5. 对动画图像的支持。
  6. 可以自定义和组合的转换,可在下载后立即应用于图像。
  7. 可以自定义加载器(如照片库)来扩展图像加载功能。
  8. 加载中的indicator显示。
  9. 保证不会下载相同的URL。
  10. 下载过程或者资源保存过程用到了GCD和ARC。
  11. 提前将获取到的图片放到主线程,保证不会阻塞主线程。

获取图片缓存

在图片加载的方法实现中,可以看到有比较重要的两个方法:一个是获取图片缓存,另一个是从网络下载图片。 在这一节,我们先看获取图片缓存:

objectivec 复制代码
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock;

点击方法进入查看其实现:

objectivec 复制代码
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock {
    // 如果没传参数key就直接回调并返回,就不继续向下执行了
    if (!key) {
        if (doneBlock) {
            doneBlock(nil, nil, SDImageCacheTypeNone);
        }
        return nil;
    }
    
    // 先根据key查找内存中是否有缓存
    UIImage *image = [self imageFromMemoryCacheForKey:key];
    // 如果有缓存图片,并且没设置强制从硬盘中查找缓存,就直接回调并返回了
    BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryDataWhenInMemory));
    if (shouldQueryMemoryOnly) {
        if (doneBlock) {
            doneBlock(image, nil, SDImageCacheTypeMemory);
        }
        return nil;
    }
    
    // 生成一个操作对象
    NSOperation *operation = [NSOperation new];
    // 生成一个查询硬盘缓存的代码块
    void(^queryDiskBlock)(void) =  ^{
        // 如果操作取消就直接返回,不执行回调
        if (operation.isCancelled) {
            // do not call the completion if cancelled
            return;
        }
        
        // 生成一个自动释放池
        @autoreleasepool {
            // 根据key查找硬盘中是否有缓存
            NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
            UIImage *diskImage;
            SDImageCacheType cacheType = SDImageCacheTypeDisk;
            if (image) {
                // 如果内存中有缓存
                diskImage = image;
                cacheType = SDImageCacheTypeMemory;
            } else if (diskData) {
                // 如果内存中没有缓存但是硬盘中有缓存
                diskImage = [self diskImageForKey:key data:diskData];
                if (diskImage && self.config.shouldCacheImagesInMemory) {
                    NSUInteger cost = SDCacheCostForImage(diskImage);
                    [self.memCache setObject:diskImage forKey:key cost:cost];
                }
            }
            
            // 如果设置了同步查询硬盘缓存的选项就直接调用,否则就主队列异步回调
            if (doneBlock) {
                if (options & SDImageCacheQueryDiskSync) {
                    doneBlock(diskImage, diskData, cacheType);
                } else {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        doneBlock(diskImage, diskData, cacheType);
                    });
                }
            }
        }
    };
    
    // 如果设置了同步查询硬盘缓存的选项就直接调用,否则就自定义串行队列异步回调
    if (options & SDImageCacheQueryDiskSync) {
        queryDiskBlock();
    } else {
        dispatch_async(self.ioQueue, queryDiskBlock);
    }
    
    return operation;
}

获取图片缓存的逻辑还是很清晰的:

  • 首先查找在内存中的缓存,再根据设置的选项决定要不要继续查找。
  • 然后根据设置的选项决定是同步还是异步查找硬盘中的缓存。
  • 接着根据设置的选项决定要不要把硬盘中的缓存图片缓存到内存中。
  • 最后进行回调数据。

缓存机制

独立的异步图像下载

可能会用到单独的异步图片下载,则一定要用- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;来建立一个SDWebImageDownLoader 的实例。这样就可以有下载进度的回调和下载完成的回调,可以在回调完成进度条相关的操作和显示图片相关的操作。

独立的异步图像缓存

SDImageCache类提供一个管理缓存的单例类。

objectivec 复制代码
SDImageCache *imageCache = [SDImageCache sharedImageCache];

查找和缓存图片时以URL作为key。(先查找内存,如果内存不存在该图片,再查找硬盘;查找硬盘时,以URL的MD5值作为key)。

查找机制如下:

  • Memory(内存)中查找:SDImageCache 类的 queryDiskCacheForKey 方法用于查询图片缓存。queryDiskCacheForKey 方法先会查询 Memory Cache ,如果查找到就直接返回,反之进入下面的硬盘查找。
  • Disk(磁盘) 中查找:如果 Memory Cache 查找不到, 就会查询 Disk Cache。就是如果 Disk Cache 查询成功,会把得到的图片再次设置到 Memory Cache 中, 以便最大化那些高频率展现图片的效率。如果找不到就进入下面的网络下载。

缓存机制如下:

  • 内存缓存的处理是使用 NSCache 对象来实现的。NSCache 是一个类似于集合的容器。它存储 key-value 对,这一点类似于 NSDictionary 类。 我们通常用使用缓存来临时存储短时间使用但创建昂贵的对象。重用这些对象可以优化性能,因为它们的值不需要重新计算。另外一方面,这些对象对于程序来说不是紧要的,在内存紧张时会被丢弃,所以有Disk(硬盘)缓存清理策略。
  • SDWebImage 使用 NSFileManager 对象来实现磁盘缓存,图片存储的位置位于Cache文件夹。另外,SDImageCache 还定义了一个串行队列,来异步存储图片。 SDImageCache 提供了大量方法来缓存、获取、移除及清空图片。而对于每个图片,为了方便地在内存或磁盘中对它进行这些操作,我们需要一个 key 值来索引它。 在内存中,我们将其作为 NSCache 的 key 值,而在磁盘中,我们用这个 key 作为图片的文件名。 对于一个远程服务器下载的图片,其 url 理所当然作为这个 key 值。


核心类:

  • SDWebImageDownloader: 负责维持图片的下载队列,是一个单例对象
  • SDWebImageDownloaderOperation: 负责真正的图片下载请求,一个自定义的并行Operation子类
  • SDImageCache: 负责SDWebImage的缓存工作,是一个单例对象
  • SDWebImageManager: 是总的管理类,维护了一个SDWebImageDownloader实例和一个SDImageCache实例,是下载与缓存的桥梁
  • SDWebImageDecoder: 负责图片的解压缩
  • SDWebImagePrefetcher: 负责图片的预取
  • UIImageView+WebCache: 和其他的扩展都是与用户直接打交道的。

概念框架

  • UIImageView+WebCache和UIButton+WebCache直接为表层的UIKit框架提供接口。
  • SDWebImageManger负责处理和协调SDWebImageDownloader和SDWebImageCache,并与 UIKit层进行交互。
  • SDWebImageDownloaderOperation真正执行下载请求,最底层的两个类为高层抽象提供支持。

这段时间主要先梳理源码的框架,以及源码的基础内容,没有时间对源码进行深入解读。

相关推荐
秃头佛爷10 分钟前
Python学习大纲总结及注意事项
开发语言·python·学习
dayouziei2 小时前
java的类加载机制的学习
java·学习
dsywws6 小时前
Linux学习笔记之vim入门
linux·笔记·学习
晨曦_子画6 小时前
3种最难学习和最容易学习的 3 种编程语言
学习
城南vision7 小时前
Docker学习—Docker核心概念总结
java·学习·docker
ctrey_7 小时前
2024-11-1 学习人工智能的Day20 openCV(2)
人工智能·opencv·学习
2401_865854887 小时前
iOS应用想要下载到手机上只能苹果签名吗?
后端·ios·iphone
十年之少7 小时前
由中文乱码引来的一系列学习——Qt
学习
u0101526588 小时前
STM32F103C8T6学习笔记2--LED流水灯与蜂鸣器
笔记·stm32·学习
王俊山IT9 小时前
C++学习笔记----10、模块、头文件及各种主题(二)---- 预处理指令
开发语言·c++·笔记·学习