SDWebImage源代码分析(下)
来源:互联网 发布:数控折弯机编程操作 编辑:程序博客网 时间:2024/05/23 02:15
10. SDImageCache 图片缓存
这个类就管理缓存相关逻辑,本地硬盘缓存,内存缓存,内存告警时候的处理,图片过期处理,后台运行处理
图片内存缓存是用NSCache来管理
图片写入到硬盘是放在一个serial queue里,一个线程顺序的写入到本地
if (toDisk)
{
dispatch_async(self.ioQueue, ^
{
NSData *data = imageData;
if (!data)
{
if (image)
{
TARGET_OS_IPHONE
data = UIImageJPEGRepresentation(image, (CGFloat)1.0);
se
data = [NSBitmapImageRep representationOfImageRepsInArray:image.representations usingType: NSJPEGFileType properties:nil];
dif
}
}
if (data)
{
// Can't use defaultManager another thread
NSFileManager *fileManager = NSFileManager.new;
if (![fileManager fileExistsAtPath:_diskCachePath])
{
[fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
}
[fileManager createFileAtPath:[self defaultCachePathForKey:key] contents:data attributes:nil];
}
});
}
检查本地硬盘是否有缓存的图片,也是在这个queue里做的
- (BOOL)diskImageExistsWithKey:(NSString *)key
{
__block BOOL exists = NO;
dispatch_sync(_ioQueue, ^
{
exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key]];
});
return exists;
}
删除本地硬盘缓存图片文件:
if (fromDisk)
{
dispatch_async(self.ioQueue, ^
{
[[NSFileManager defaultManager] removeItemAtPath:[self defaultCachePathForKey:key] error:nil];
});
}
总之,涉及到IO操作的,都是单独的线程来做,这样总体来说用户体验是最佳的。
11.SDWebImageManager总体的image管理类
其对外暴露的接口返回的是id类型,实现了协议(id<SDWebImageOperation>)
返回出去其实是SDWebImageCombinedOperation
它什么都不做,仅仅保存两个东西:(一个block,可以取消下载operation, 一个operation,去查询本地硬盘缓存的operation)
这样就很清晰了,这个对外返回的SDWebImageCombinedOperation,要么查到缓存,要么没查到,可以去下载,也可以取消下载
SDWebImageCombinedOperation封装的很好,给用户看到的是透明的,对外可以找到缓存或者下载到图片,或者由用户决定取消下载图片
Block的使用
@property (copy, nonatomic) SDWebImageNoParamsBlockcancelBlock;
if (self.isCancelled) {
if (cancelBlock) {
cancelBlock();
}
_cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we willget crashes
} else {
_cancelBlock =[cancelBlock copy];
}
SDWebImage源码阅读心得
SDWebImage是一个异步下载图片的开源模块。
实现的业务功能,是异步下载网络上的图片,为上层屏蔽实现细节,提供接口调用。
一张图片在Cocoa中用UIImage对象来表现,而要在视图上显示,则需要UIImageView,显然它是视图对象。其组合依赖关系
UIImageView->UIImage->图像数据
SDWebImage源码阅读后,最大的感受是其职责明确,即各个类功能单一,权责明确。类之间通过组合实现业务功能,通过Objective-C的Category(类别)来扩展基础框架Cocoa类的功能。
而多张图片,就会有多个任务操作,多个操作显然会放在一个下载队列中(NSOperationQueue),而这个下载队列downloadQueue由SDWebImageDownloader类的单例来管理。在SDWebImage模块内部,凡是有图片URL需要下载,就丢给SDWebImageDownloader类的单例,由它负责下载,实现并行的异步下载。
扩展后的UIImageView需要显示一张来自网络上的图片(URL), 那么它会把这个任务交给大内总管SDWebImageManager类的单例,SDWebImageManager首先会询问图片存储管理者SDImageCache类的实例,该URL对应的图片有没有在本地(内存或硬盘上),如果有,则读取图片数据返回,如果没有,则把这个任务交给SDWebImageDownloader类的单例,去下载网络上的图片,下载完成,则先由SDImageCache类的实例存储到本地,再告诉UIImageView这边已经获取到图片了,你可以显示了,注意,这其中的过程都是异步的。显然SDWebImageManager管理着这样的一个个任务(Operation),它把这些任务存储在了一个数组中:runningOperation。SDWebImageManager关心的是URL对应的图片UIImage, 至于UIImage是在本地SDWebCache获取的,还是通过SDWebImageDownloader从网络上获取的,它不关心,怎么获取的也不关心,这由你们兄弟俩SDWebCache和SDWebImageDownloader负责,我(SDWebImageManager)只在的记账本(runningOpertions数组)上记录有这本帐(SDWebImageCombinedOperation),到时候,处理好后,把结果告诉我就行。组合依赖调用如下示意:
核心函数的主要过程如下如下:
撤销当前UIImageView实例关联的获取图像的任务operation;
把传入参数URL与当前UIImageView实例关联起来;
根据需要设置替代图片(placeholder);
把URL丢给SDWebImageManager的单例(其实是调用其一个函数,记为函数A),叫它去获取图片;
调用SDWebImageManager单例函数后异步返回一个operation给UIImageView,UIImageView存储这个任务,其实是存储在UIView的关联字典中,待需要时撤销该operation;
待SDWebImageManager找到图片时,回调完成函数,在完成函数中告知UIImageView,你可以重画了,即setNeedsLayout;
结束。
A函数的神秘面纱如下,看清楚了:
- (id<SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image,
NSError *error,
SDImageCacheType cacheType,
BOOL finished,
NSURL *imageURL);
其具体处理逻辑如下:
1 创建SDWebImageCombinedOperation实例,并把这个实例加入runningOperations数组中,显然一个图片URL会产生一个operation,并记录在runningOperations数组中;
2 计算URL对应的KEY,依据key向SDWebCache查询是否有这样key的UIImage图片存在,异步返回,通过回调函数告之SDWebImageManager结果, 记为函数B;
3 在SDWebCache的查询done回调函数中,如果图片不存在,并判定需要下载该URL图片,则计算下载参数SDWebImageDownloaderOptions, 则向SDWebImageDownloader请求下载该URL对应的图片,异步返回,记为函数C,而后设置SDWebImageCombinedOperation实例操作的cancelBlock;
在SDWebImageDownloader的下载完成回调函数中,请求SDWebCache保存下载图片(异步),记为函数D,而后调用completedBlock回调,告之UIImageView+WebCache;
SDImageCache
SDImageCache依据KEY查询图片是否存在的B函数接口如下:
- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock;
typedefvoid(^SDWebImageQueryCompletedBlock)(UIImage *image,SDImageCacheType cacheType);
逻辑过程是:
4 在内存依据关键字查询图片是否存在,如果存在,则直接调用doneBlock回调返回;
如果不存在,则创建一个NSOperation的实例,放在ioQueue串行队列中查询在硬盘上是否存在,如果存在则把它设置在内存中来,最后通过doneBlock回调函数把结果返回给调用者。
SDWebImageDownloader
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageDownloaderOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageDownloaderCompletedBlock)completedBlock;
typedefvoid(^SDWebImageDownloaderCompletedBlock)(UIImage *image, NSData *data,NSError *error, BOOL finished);
逻辑过程如下:
1为该URL记录progressBlock, completeBlock回调函数,记录在URLCallbacks字典中;
2以URL,缓存策略等参数初始化一个NSMutableURLRequest实例 request,并设置request的http请求参数;
3以request,回调函数块初始化一个SDWebImageDownloaderOperation实例,在各回调函数块中会调用progressBlock, completeBock回调函数,记为函数D;
4设置operation队列优先级,任务执行次序,FIFO/LIFO, 把operation加入下载队列downloadQueue, 并把它返回给调用者;
总结
5 可以看出SDWebImage对于耗时较长的请求,都是异步,调用者从不等待,在回调函数块中处理请求结果;
6 接口不只在于能直接调用的类实例上的函数,还存在回调函数块,也是接口的一部分;
7 SDWebImage模块中单例充分应用,单例是模块内分层的依据,一个单例全权负责某方面的工作;
8 OBJECTI-C是的C超集合,明显有C的烙印,对于每一个.h/.m文件,组成一个小模块,.h中先如C语言般声明,接着是OBJECITV-C的部分Interface,类的声明,而.m中也是如C语言般的实现,再是OBJECTIVE-C中的类扩展和实现,.h中对外可见,.m中对内可见,对外不可见,显然遵守C的面向模块的设计思路;
换元思想…,那么SDWebImage这个框架可以应用在很多方面…
- SDWebImage源代码分析(下)
- iOS SDWebImage源代码分析(上)
- SDWebImage源代码分析
- SDWebImage分析--源代码详细分析
- SDWebImage源代码解析(一)Cache
- SDWebImage源代码解析(二)Downloader
- SDWebImage源代码解析(三)Utils
- SDWebImage源代码解析(四)Categories
- SDWebImage源代码理解
- SDWebImage源代码阅读(一)
- SDWebImage源代码阅读(二)
- SDWebImage源代码阅读(三)
- SDWebImage源代码阅读(四)
- SDWebImage源码分析
- SDWebImage源码分析
- SDWebImage 缓存机制分析
- 图片缓存SDWebImage分析
- 【转】SDWebImage实现分析
- bzoj1822 [JSOI2010]Frozen Nova 冷冻波
- 学习笔记:jQuery deferred对象的整理2
- SYN,ICMP, UDP Flood攻击原理与防护
- 线性表自测题
- javaScript实现HTML页面分屏滚动效果
- SDWebImage源代码分析(下)
- 2015年第六届蓝桥杯C/C++程序设计本科B组决赛第二题
- C语言的选择算法
- linux下modprobe: module ath.ko not found in modules.dep
- C/C++ memmove与memcpy的区别及实现
- 完美数列
- servlet四大域总结
- 2016.03.27培训日记
- Hibernate对象状态