SDWebImage 源码分析

栏目: IOS · 发布时间: 5年前

内容简介:主要围绕三个方面来阐述这是从 github SDWebImage 地址下载的图. 图片说明了整个图片加载的时序.下面根这源码来验证一下上面说的知识 根据 Github 上面提供的整个 SD 的类图可知,主要是

主要围绕三个方面来阐述

  • 加载流程
  • 缓存模块
  • 下载模块

加载流程

SDWebImage 源码分析

这是从 github SDWebImage 地址下载的图. 图片说明了整个图片加载的时序.

双缓存

下面根这源码来验证一下上面说的知识 根据 Github 上面提供的整个 SD 的类图可知,主要是 SDWebImageManager 在操作管理查找流程. 我们就根据大家使用的最多的方法, 来一步步跟踪.

  1. 通常情况下,我们使用这个方法对图片进行加载。
UIImageView+WebCache.h 文件中
-(void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
复制代码
  1. 查找 sd_internalSetImageWithURL 方法.
UIView+WebCache.h 文件中
sd_internalSetImageWithURL ....
复制代码
  1. 如果你设置了 PlaceholderImage, 他会先去显示你的 placeholderImage
if (!(options & SDWebImageDelayPlaceholder)) {
        dispatch_main_async_safe(^{
            [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:SDImageCacheTypeNone imageURL:url];
        });
    }
复制代码
  1. 继续去 SDWebImageManager 中的 loadImageWithURL 查找图片
id <SDWebImageOperation> operation = [manager loadImageWithURL:url options:options context:context progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
复制代码
  1. 然后调用 callCacheProcessForOperation 进行缓存查找操作
BOOL shouldQueryCache = (options & SDWebImageFromLoaderOnly) == 0;
if (shouldQueryCache) {
	// 缓存查找
}else {
	// 进行下载操作
}
复制代码
  1. 接上缓存查找过程, 回去 SDImageCache 中的 queryImageForKey 方法继续缓存查找
-(id<SDWebImageOperation>)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock {
复制代码
  1. 接下来到 queryCacheOperationForKey 方法

    • 首先去内存中找,如果有就用 Block 的方式传递到上层显示
    // First check the in-memory cache...
    UIImage *image = [self imageFromMemoryCacheForKey:key];
    复制代码
    • 否则就去 Disk 查找
    NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
    复制代码
    • 如果 Disk 有就返回,并且把这个值存入 MemoryCache 中,这样就可以再下次查找中更快的找到对应的图片信息
    [self.memCache setObject:diskImage forKey:key cost:cost];
    复制代码
  2. 如果没找到就去下载图片

callDownloadProcessForOperation
复制代码
  1. 进入下载流程, 生成 SDWebImageDownloadToken 对象.就行下载
[self callStoreCacheProcessForOperation:operation url:url options:options context:context downloadedImage:downloadedImage downloadedData:downloadedData finished:finished progress:progressBlock completed:completedBlock];
复制代码
  1. 下载完成就行存储
[self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey cacheType:storeCacheType completion:nil];
复制代码
* 分别存储到内存和磁盘
```
-(void)storeImage:(nullable UIImage *)image
     imageData:(nullable NSData *)imageData
        forKey:(nullable NSString *)key
      toMemory:(BOOL)toMemory
        toDisk:(BOOL)toDisk
    completion:(nullable SDWebImageNoParamsBlock)completionBlock {
``` 
复制代码
  1. 返回数据显示
[self callCompletionBlockForOperation:operation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url];
复制代码

到此整个图片加载流程就完了.

SDWebImage 源码分析

缓存模块

下图是最新的 SDWebImage 的文件结构,这里主要看看 Cache 板块

SDWebImage 源码分析
  • 首先介绍这些文件是干啥的(记得之前的 Cache 没这么多文件)
    • SDImageCacheConfig.h SDImageCacheConfig.m 这两个文件是来做一些设置
    • SDMemoryCache.h SDMemoryCache.m 是内存缓存相关的操作
    • SDDiskCache.h SDDiskCache.m 是磁盘缓存相关的操作
    • SDImageCacheDefine.h SDImageCacheDefine.m 主要是为 SDImageCache 定义了一些协议
    • SDImageCachesManager.h SDImageCachesManager.m 主要对 Cache 删除和添加
    • SDImageCache.h SDImageCache.m 操作 SDDiskCacheSDMemoryCache

首先先看设置文件 SDImageCacheConfig

* 定义了默认的磁盘缓存时间, 默认为 1 周 `kDefaultCacheMaxDiskAge = 60 * 60 * 24 *7;`
* shouldDisableiCloud 是否使用 iCloud
* shouldCacheImagesInMemory 是否使用内存缓存
* shouldUseWeakMemoryCache 是否使用弱应用内存缓存
* shouldRemoveExpiredDataWhenEnterBackground 是否删除超过日期的数据
* maxDiskAge 最大磁盘缓存周期为 `1` 周
* maxDiskSize 最大磁盘缓存大小.默认为 0,意味着没有大小限制
* maxMemoryCost 内存缓存大小,默认为 0,意味着没有大小限制
* maxMemoryCount 内存缓存的最大数量,默认 0
* diskCacheExpireType  磁盘缓存失效的类型(用于删除使用)
复制代码

SDMemoryCache

* `SDMemoryCache` 是继承自 系统的 `NSCache`.
* 这个类主要是操作内存,删除,保存的操作
* 首先注册了内存警告通知 `UIApplicationDidReceiveMemoryWarningNotification`
* 保存
	- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g {
		[super setObject:obj forKey:key cost:g];
		if (!self.config.shouldUseWeakMemoryCache) {
    		return;
	    }
	    if (key && obj) {
        // Store weak cache
    		SD_LOCK(self.weakCacheLock);
        [self.weakCache setObject:obj forKey:key];
	      SD_UNLOCK(self.weakCacheLock);
	    }
	}
	
	Note: 这里的保存方法是做了两次保存操作
		1. 使用 [Super setObject:obj forKey:key cost: g] 先给父类设置,也就是给系统的 NSCache 设置缓存
		2. 然后在给当前缓存内的 `NSMapTable` 设置值
		3. 这样也就是拿空间换时间的操作,相当于在内存中是有两份数据的,如果第一份没有,就去拿第二份,这样就保证了快速度的响应. 

* 取值
	-(id)objectForKey:(id)key {
		 id obj = [super objectForKey:key];
	    if (!self.config.shouldUseWeakMemoryCache) {
		      return obj;
	    }
		  if (key && !obj) {
 		   // Check weak cache
 	   	SD_LOCK(self.weakCacheLock);
     	   obj = [self.weakCache objectForKey:key];
   	   SD_UNLOCK(self.weakCacheLock);
   	   if (obj) {
          // Sync cache
          NSUInteger cost = 0;
          if ([obj isKindOfClass:[UIImage class]]) {
              cost = [(UIImage *)obj sd_memoryCost];
          }
          [super setObject:obj forKey:key cost:cost];
      }
	    }
  	  return obj;
	}
	1. 先去 `super` 取值
	2. 如果木有就去 `NSMapTable` 中取值
复制代码

SDDiskCache

* 使用 NSFileManager 管理图片缓存
* 根据 `key` 在它 SDDiskCacheFileNameForKey 方法中,使用 `CC_MD5` 生成一个 新的  `Key`, 转换成 url,存放 data.
* 还有一点就是清理过期的数据,有两种方式
	1. SDImageCacheConfigExpireTypeAccessDate 根据访问时间
	2. SDImageCacheConfigExpireTypeModificationDate 修改时间(默认)
	3. 根据 self.config.maxDiskAge 来对比删除超过时间的图片
	4. 根据 self.config.maxDiskSize 来删除磁盘缓存的数据,清理到self.config.maxDiskSize /2 为止.
复制代码

SDImageCachesManager

* 主要是操作 `SDImageCache` 类,对缓存就行 `存储`, `删除`, `清理`, `查询`
复制代码

SDImageCacheConfig

* 主要是对图片的 `Decode` 操作
复制代码

SDImageCache

* 值得说的是,他在这里监听了两个系统通知
1. UIApplicationWillTerminateNotification
2. UIApplicationDidEnterBackgroundNotification
当这两个方法执行时,其实是做了一件事情,就是清理磁盘缓存 
[self.diskCache removeExpiredData];
复制代码

下载模块

SDWebImageDownloaderConfig

* 设置最大并发数 maxConcurrentDownloads ,默认是 6
* 设置下载超时时间 downloadTimeout ,默认 15s
* 下载执行顺序 executionOrder , 默认先进先出
复制代码

SDWebImageDownloader

Note: 总结就是 使用 系统 NSURLSession 创建 task ,在本类中它实现了 NSURLSessionTaskDelegate, 当数据下载完成,就去显示.
	* 主要是设置下载队列
  	* 拼接 HTTPHeader 
	* 组装 SDWebImageDownloaderOperation 
  	* 设置 Credential
	* 配置 NSOperation 的优先级
	* 返回一个 SDWebImageDownloaderOperation
	* 虽然设置了 NSURLSessionTaskDelegate 的代理在这个类中,但是实际还是把结果交费给了 SDWebImageDownloaderOperation, 统一处理
	
	NSOperation<SDWebImageDownloaderOperation> *dataOperation = [self operationWithTask:dataTask];
    if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:didReceiveResponse:completionHandler:)]) {
    		[dataOperation URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler];
	 } else {
  	  if (completionHandler) {
     	   completionHandler(NSURLSessionResponseAllow);
   		 }
	}
复制代码

SDWebImageDownloaderOperation

Note: 他是集成自 NSOperation, 重写了 Start 方法
	* 在 Start 时,如果 app 进入后台,就取消下载.
	* 设置 NSURLSession 之后就下载任务
	* 其中手动(KVC)出发了 isFinished isExecuting
	* 然后就是在 NSURLSessionTaskDelegate,NSURLSessionDataDelegate,设置显示就回调
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Mastering Regular Expressions, Second Edition

Mastering Regular Expressions, Second Edition

Jeffrey E F Friedl / O'Reilly Media / 2002-07-15 / USD 39.95

Regular expressions are an extremely powerful tool for manipulating text and data. They have spread like wildfire in recent years, now offered as standard features in Perl, Java, VB.NET and C# (and an......一起来看看 《Mastering Regular Expressions, Second Edition》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器