内容简介:主要围绕三个方面来阐述这是从 github SDWebImage 地址下载的图. 图片说明了整个图片加载的时序.下面根这源码来验证一下上面说的知识 根据 Github 上面提供的整个 SD 的类图可知,主要是
主要围绕三个方面来阐述
- 加载流程
- 缓存模块
- 下载模块
加载流程
这是从 github SDWebImage 地址下载的图. 图片说明了整个图片加载的时序.
双缓存
下面根这源码来验证一下上面说的知识 根据 Github 上面提供的整个 SD 的类图可知,主要是 SDWebImageManager
在操作管理查找流程. 我们就根据大家使用的最多的方法, 来一步步跟踪.
- 通常情况下,我们使用这个方法对图片进行加载。
UIImageView+WebCache.h 文件中 -(void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder 复制代码
- 查找
sd_internalSetImageWithURL
方法.
UIView+WebCache.h 文件中 sd_internalSetImageWithURL .... 复制代码
- 如果你设置了 PlaceholderImage, 他会先去显示你的 placeholderImage
if (!(options & SDWebImageDelayPlaceholder)) { dispatch_main_async_safe(^{ [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:SDImageCacheTypeNone imageURL:url]; }); } 复制代码
- 继续去 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) { 复制代码
- 然后调用
callCacheProcessForOperation
进行缓存查找操作
BOOL shouldQueryCache = (options & SDWebImageFromLoaderOnly) == 0; if (shouldQueryCache) { // 缓存查找 }else { // 进行下载操作 } 复制代码
- 接上缓存查找过程, 回去
SDImageCache
中的queryImageForKey
方法继续缓存查找
-(id<SDWebImageOperation>)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { 复制代码
-
接下来到
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]; 复制代码
-
如果没找到就去下载图片
callDownloadProcessForOperation 复制代码
- 进入下载流程, 生成
SDWebImageDownloadToken
对象.就行下载
[self callStoreCacheProcessForOperation:operation url:url options:options context:context downloadedImage:downloadedImage downloadedData:downloadedData finished:finished progress:progressBlock completed:completedBlock]; 复制代码
- 下载完成就行存储
[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 { ``` 复制代码
- 返回数据显示
[self callCompletionBlockForOperation:operation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; 复制代码
到此整个图片加载流程就完了.
缓存模块
下图是最新的 SDWebImage 的文件结构,这里主要看看 Cache 板块
- 首先介绍这些文件是干啥的(记得之前的 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 操作
SDDiskCache
和SDMemoryCache
首先先看设置文件 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,设置显示就回调 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 以太坊源码分析(36)ethdb源码分析
- [源码分析] kubelet源码分析(一)之 NewKubeletCommand
- libmodbus源码分析(3)从机(服务端)功能源码分析
- [源码分析] nfs-client-provisioner源码分析
- [源码分析] kubelet源码分析(三)之 Pod的创建
- Spring事务源码分析专题(一)JdbcTemplate使用及源码分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。