ios源代码分析--SDWebImage

SDWebImage

该框架的主要作用就是:一个异步下载图片并且支持缓存UIImageView分类

1、该框架中最常用到的方法就是:(不仅可以加载图片,也可以对Button进行加载)

[self.imageView sd_setImageWithURL:[NSURL URLWithString:@“url”] placeholderImage:[UIImage imageNamed:@“图片.png”]];//占位图

2、该框架的搭建方式:

UIImageView+WebCache 和 UIButton+WebCache 直接为表层的 UIKit 框架提供接口, 而 SDWebImageManger 负责处理和协调 SDWebImageDownloader 和 SDWebImageCache. 并与 UIKit 层进行交互, 而底层的一些类为更高层级的抽象提供支持.

该方法的实现:是UIImageView+WebCache中的核心方法

-(void)sd_setImageViewWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder

{

    [self sd_setImageViewWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];

}

该框架中所有操作实际上都是通过一个operationDictionary来管理,这个字典实际上是动态的添加到UIView上的属性,主要是因为这个operationDictionary需要在UIButton和UIImageView上重用,所以需要添加它到根类上面。

[self sd_cancelImageLoadOperationWithKey:@“UIImageViewImageLoad”];//该方法主要保证没有当前正在进行的异步下载操作,不会和即将进行的操作发生冲突。该方法会使当前UIImageView中的所有操作都被cancel.并且不会影响之后的下载操作。

3、占位图的实现:

If( !( options & SDWebImageDelayPlaceholder))

{

    Self.image = placeholder;

}

解释:如果传入的options中没有SDWebImageDelayPlaceholder(默认情况下options == 0 )那么就会给UIImageView添加一个临时的Image.

4、获取图片:

if(url)//检测传入的url是否为空,如果是非空那么一个全局的SDWebImageMangager就会调用下面的方法去获取图片。

[SDWebImageManager.sharedManager downloadImageWithURL:options:progress:completed:];

下载完成后会调用 (SDWebImageCompletionWithFinishedBlock)completedBlock 为 UIImageView.image 赋值, 添加上最终所需要的图片

dispatch_main_sync_safe(^{

    if (!wself) return;

    if (image) {

        wself.image = image;

        [wself setNeedsLayout];

    } else {

        if ((options & SDWebImageDelayPlaceholder)) {

            wself.image = placeholder;

            [wself setNeedsLayout];

        }

    }

    if (completedBlock && finished) {

        completedBlock(image, error, cacheType, url);

    }

});//其中dispatch_main_sync_safe是宏定义,主要的作用就是图像的绘制只能在主线程中完成,保证了block在主线程中执行。

该宏定义的代码为:

#define dispatch_main_sync_safe(block)\

    if ([NSThread isMainThread]) {\

        block();\

    } else {\

        dispatch_sync(dispatch_get_main_queue(), block);\

    }

5、最后在方法【SDWebImageManager.sharedManager downloadImageWithURL:options:progress:completed:]返回

Operation 的同时,也会向operationDictionary中添加一个键值对,来表示操作的正在进行:

[self sd_setImageLoadOperation:operation forKey:@“UIImageViewImageLoad”];

它将operation存储到operationDictionary中方便以后的cancel.

SDwebImageManager

1、该类是隐藏在UIImageView+WebCache背后,用来处理异步下载和图片缓存的方法,

2、也可以通过该类的downloadImageWithURL:options:progress:completed:方法来直接下载图片。

3、该类主要作用就是将UIImageView+WebCache和SDWebImageDownloader,SDImageCache之间构成一个桥梁,使得它们能够更好地协同工作。

if ([url isKindOfClass:NSString.class]) {

    url = [NSURL URLWithString:(NSString *)url];

}

if (![url isKindOfClass:NSURL.class]) {

    url = nil;

}//确定url是否能够正确的传入,如果传入参数是NSString类型就会被转换为NSURL,如果转换失败就会为url赋为空值,那么下载的这个操作就会出错。

1)获取到url,再通过url获取到对应的key,

NSString *key = [self cacheKeyForURL:url];

2)那么下一步便是在缓存中查找之前是否下载过相同的图片,通过调用queryDiskCacheForKey:done来尝试在缓存中获取图片的数据,

Operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image,SDImageCacheType cacheType){…………}];

3)假如在缓存中查找到了对应的图片,那么直接调用completedBlock回调结束这一次的图片下载操作。

Dispatch_main_sync_safe(^{

    completedBlock(image,nil,cacheType,YES,url);

});

4)如果没有找到图片,那么就会调用SDWebImageDownloader的实例方法:

Id<SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url

Options:downloaderOptions

progress:progressBlock

Completed:^(UIImage *downloadedImage,NSData *data,NSError *error,BOOL finished){}];

5)如果该方法返回了正确的downlosdedImage,那么,就会在全局缓存中存储这个图片的数据。并且调用completeBlock对UIImageView或者UIButton添加图片,或者进行其他的操作

6)最后,将subOperation的cacel操作添加到operation.cancelBlock中方便操作的取消。

SDWebImageCache

该类主要作用是维护一个内存缓存和一个可选的磁盘缓存。

1、-(NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock;//该方法的主要功能是异步的查询图片缓存,因为图片缓存可能在两个地方,该方法优先在内存中查找是否有该图片的缓存。

2、UIImage *image = [self imageFromMemoryCacheForKey:key];

该方法会在SDWebImageCache维护的缓存memCache中查找是否有对应的数据,而memCache就是一个NSCache。如果在内存中没有找到磁盘,那么就需要通过调用diskImageForKey这个方法在磁盘中进行查找,文件的名字存储采用MD5处理过后的文件名。

3、如果在磁盘中找到了对应的图片,便会将其复制到内存中,以便下次使用

SDWebImageDownloader

该类的作用是:专用的并且优化的图片异步下载器

1、核心方法是:

-(id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url

Options:(SDWebImageDownloaderOptions)options

Progress:(SDWebImageDownloaderProgressBlock)progressBlock

Completed:(SDWebImageDownloaderCompletedBlock)completedBlock;该方法直接回调了另外一个关键的方法:

- (void)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock

          andCompletedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock

                     forURL:(NSURL *)url

             createCallback:(SDWebImageNoParamsBlock)createCallback

该方法的源码是:

BOOL first = NO;

if (!self.URLCallbacks[url]) {

    self.URLCallbacks[url] = [NSMutableArray new];

    first = YES;

}

// Handle single download of simultaneous download request for the same URL

NSMutableArray *callbacksForURL = self.URLCallbacks[url];

NSMutableDictionary *callbacks = [NSMutableDictionary new];

if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy];

if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy];

[callbacksForURL addObject:callbacks];

self.URLCallbacks[url] = callbacksForURL;

if (first) {

    createCallback();

}

解读:方法会先查看这个 url 是否有对应的 callback, 使用的是 downloader 持有的一个字典 URLCallbacks.如果是第一次添加回调的话, 就会执行 first = YES, 这个赋值非常的关键, 因为 first 不为 YES 那么 HTTP 请求就不会被初始化, 图片也无法被获取.然后, 在这个方法中会重新修正在 URLCallbacks 中存储的回调块.

SDWebImageDownloaderOperation

该类就是处理HTTP请求,URL连接的类,当这个类的实例被加入队列之后,start方法会被调用,而start方法首先就会产生一个NSURLConnection.

关于面试题:SDWebImage如何为UIImageView添加图片:

SDWebImage 中为 UIView 提供了一个分类叫做 WebCache, 这个分类中有一个最常用的接口, sd_setImageWithURL:placeholderImage:, 这个分类同时提供了很多类似的方法, 这些方法最终会调用一个同时具有 option progressBlock completionBlock 的方法, 而在这个类最终被调用的方法首先会检查是否传入了 placeholderImage 以及对应的参数, 并设置 placeholderImage.

然后会获取 SDWebImageManager 中的单例调用一个 downloadImageWithURL:... 的方法来获取图片, 而这个 manager 获取图片的过程有大体上分为两部分, 它首先会在 SDWebImageCache 中寻找图片是否有对应的缓存, 它会以 url 作为数据的索引先在内存中寻找是否有对应的缓存, 如果缓存未命中就会在磁盘中利用 MD5 处理过的 key 来继续查询对应的数据, 如果找到了, 就会把磁盘中的缓存备份到内存中.

然而, 假设我们在内存和磁盘缓存中都没有命中, 那么 manager 就会调用它持有的一个 SDWebImageDownloader对象的方法 downloadImageWithURL:... 来下载图片, 这个方法会在执行的过程中调用另一个方法 addProgressCallback:andCompletedBlock:fotURL:createCallback: 来存储下载过程中和下载完成的回调, 当回调块是第一次添加的时候, 方法会实例化一个 NSMutableURLRequest 和 SDWebImageDownloaderOperation, 并将后者加入 downloader 持有的下载队列开始图片的异步下载.

而在图片下载完成之后, 就会在主线程设置 image 属性, 完成整个图像的异步下载和配置

猜你喜欢

转载自blog.csdn.net/minld/article/details/81672232