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 属性, 完成整个图像的异步下载和配置