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 (copynonatomicSDWebImageNoParamsBlockcancelBlock;

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-CCategory(类别)来扩展基础框架Cocoa类的功能。

 

而多张图片,就会有多个任务操作,多个操作显然会放在一个下载队列中(NSOperationQueue),而这个下载队列downloadQueueSDWebImageDownloader类的单例来管理。在SDWebImage模块内部,凡是有图片URL需要下载,就丢给SDWebImageDownloader类的单例,由它负责下载,实现并行的异步下载。

 

扩展后的UIImageView需要显示一张来自网络上的图片(URL), 那么它会把这个任务交给大内总管SDWebImageManager类的单例,SDWebImageManager首先会询问图片存储管理者SDImageCache类的实例,URL对应的图片有没有在本地(内存或硬盘上),如果有,则读取图片数据返回,如果没有,则把这个任务交给SDWebImageDownloader类的单例,去下载网络上的图片,下载完成,则先由SDImageCache类的实例存储到本地,再告诉UIImageView这边已经获取到图片了,你可以显示了,注意,这其中的过程都是异步的。显然SDWebImageManager管理着这样的一个个任务(Operation),它把这些任务存储在了一个数组中:runningOperationSDWebImageManager关心的是URL对应的图片UIImage, 至于UIImage是在本地SDWebCache获取的,还是通过SDWebImageDownloader从网络上获取的,它不关心,怎么获取的也不关心,这由你们兄弟俩SDWebCacheSDWebImageDownloader负责,我(SDWebImageManager)只在的记账本(runningOpertions数组)上记录有这本帐(SDWebImageCombinedOperation),到时候,处理好后,把结果告诉我就行。组合依赖调用如下示意:

 

   核心函数的主要过程如下如下:

撤销当前UIImageView实例关联的获取图像的任务operation;

把传入参数URL与当前UIImageView实例关联起来;

根据需要设置替代图片(placeholder);

URL丢给SDWebImageManager的单例(其实是调用其一个函数,记为函数A),叫它去获取图片;

调用SDWebImageManager单例函数后异步返回一个operationUIImageViewUIImageView存储这个任务,其实是存储在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,依据keySDWebCache查询是否有这样keyUIImage图片存在,异步返回,通过回调函数告之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字典中;

2URL,缓存策略等参数初始化一个NSMutableURLRequest实例 request,并设置requesthttp请求参数;

3request,回调函数块初始化一个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这个框架可以应用在很多方面

0 0
原创粉丝点击