文章目录
SDWebImage
SDWebImage具有缓存支持的异步映像下载程序。并添加了像UI元素分类类UIImageView、UIButton、MKAnnotationView,可以直接为这些UI元素添加图片。
日常使用
在日常的使用中,通常是加载网络图片到UIImageView上展示,所以一般在需要使用SDWebImage的文件中只引用#import "UIImageView+WebCache.h"头文件。
最简单的加载方式是只加载图片地址:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:imageView];
[imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]];
当然,SDWebImage也提供了其他的加载方法,不过点击方法进入查看后,发现最终都是调用其全能方法:
- (void)sd_setImageWithURL:(nullable NSURL *)url {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
}
全能方法除了必需的的图片地址,还提供了占位图、可选项、加载进度和完成回调。
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
紧接着我们点击进入全能方法中:
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:nil
setImageBlock:nil
progress:progressBlock
completed:completedBlock];
}
可以发现,全能方法并没有什么实际的实现,只是对另一个方法的封装。
一些主要功能
- 对
UIImageView
、UIButton
、MKAnnotationView
添加Web图像和告诉缓存管理 - 异步图像下载器
- 具有自动缓存到期处理的异步内存+磁盘映像缓存
- 背景图像解压缩
- 对动画图像的支持
- 可以自定义和组合的转换,可在下载后立即应用于图像
- 可以自定义加载器(如照片库)来扩展图像加载功能
- 加载中的
indicator
显示 - 保证不会下载相同的
URL
- 下载过程或者资源保存过程用到了
GCD
和ARC
- 提前将获取到的图片放到主线程,保证不会阻塞主线程
获取图片缓存
在图片加载的方法实现中,可以看到有比较重要的两个方法,一个是获取图片缓存,另一个是从网络下载图片。在这一节,我们先看获取图片缓存:
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock;
点击方法进入查看其实现:
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock {
// 如果没传参数key就直接回调并返回,就不继续向下执行了
if (!key) {
if (doneBlock) {
doneBlock(nil, nil, SDImageCacheTypeNone);
}
return nil;
}
// 先根据key查找内存中是否有缓存
UIImage *image = [self imageFromMemoryCacheForKey:key];
// 如果有缓存图片,并且没设置强制从硬盘中查找缓存,就直接回调并返回了
BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryDataWhenInMemory));
if (shouldQueryMemoryOnly) {
if (doneBlock) {
doneBlock(image, nil, SDImageCacheTypeMemory);
}
return nil;
}
// 生成一个操作对象
NSOperation *operation = [NSOperation new];
// 生成一个查询硬盘缓存的代码块
void(^queryDiskBlock)(void) = ^{
// 如果操作取消就直接返回,不执行回调
if (operation.isCancelled) {
// do not call the completion if cancelled
return;
}
// 生成一个自动释放池
@autoreleasepool {
// 根据key查找硬盘中是否有缓存
NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
UIImage *diskImage;
SDImageCacheType cacheType = SDImageCacheTypeDisk;
if (image) {
// 如果内存中有缓存
diskImage = image;
cacheType = SDImageCacheTypeMemory;
} else if (diskData) {
// 如果内存中没有缓存但是硬盘中有缓存
diskImage = [self diskImageForKey:key data:diskData];
if (diskImage && self.config.shouldCacheImagesInMemory) {
NSUInteger cost = SDCacheCostForImage(diskImage);
[self.memCache setObject:diskImage forKey:key cost:cost];
}
}
// 如果设置了同步查询硬盘缓存的选项就直接调用,否则就主队列异步回调
if (doneBlock) {
if (options & SDImageCacheQueryDiskSync) {
doneBlock(diskImage, diskData, cacheType);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
doneBlock(diskImage, diskData, cacheType);
});
}
}
}
};
// 如果设置了同步查询硬盘缓存的选项就直接调用,否则就自定义·串行队列异步回调
if (options & SDImageCacheQueryDiskSync) {
queryDiskBlock();
} else {
dispatch_async(self.ioQueue, queryDiskBlock);
}
return operation;
}
获取图片缓存的逻辑还是很清晰的:
- 首先查找在内存中的缓存,再根据设置的选项决定要不要继续查找。
- 然后根据设置的选项决定是同步还是异步查找硬盘中的缓存。
- 接着根据设置的选项决定要不要把硬盘中的缓存图片缓存到内存中。
- 最后进行回调数据
缓存机制
独立的异步图像下载
可能会用到单独的异步图片下载,则一定要用
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
来建立一个SDWebImageDownLoader
的实例。这样就可以有下载进度的回调和下载完成的回调,可以在回调完成进度条相关的操作和显示图片相关的操作。
独立的异步图像缓存
SDImageCache
类提供一个管理缓存的单例类。
SDImageCache *imageCache = [SDImageCache sharedImageCache];
查找和缓存图片时以URL
作为key
。(先查找内存,如果内存不存在该图片,再查找硬盘;查找硬盘时,以URL
的MD5
值作为key
).
图片加载全过程
- 我们在使用
SDWebImage
时调用了[imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]];
这个简单的分类方法,然后就静静的等着图片被设置到UIImageView
类对象上。 - 经过一系列调用,我们首先来到
UIView+WebCache
分类中,在这个分类中,首先保障了图片加载的唯一性,然后就开始了核心的加载操作。 - 接着就进入了
SDWebImageManager
类中,在这个类中,首先去查找是否有缓存,没有缓存的话才去服务器下载。 - 想要查找缓存我们要进入
SDImageCache
这个类中,在这个类中,首先去内存中查看是否有对应的缓存,如果没有再去硬盘中查找是否有对应的缓存,但是从硬盘中获取的是图片的数据,要想获得图片还要经历解码、缩放和解压。当然如果都没有缓存的话就去下载。 - 负责下载的是
SDWebImageDownloader
这个类,在这个类中,将图片的下载操作封装成了自定义的一个类SDWebImageDownloaderOperation
,然后添加到了操作队列中。 - 当操作队列调用这个操作时,会调用操作对象的
- (void)start
方法,在重写的这个方法中,生成了任务对象dataTask
,并调用resume
开始执行任务。 - 因为
SDWebImageDownloaderOperation
类遵守了dataTask
对象的协议,所以dataTask
执行的结果会通过代理方法进行回调。在代理方法中,获取并保存了服务器返回的数据,并在任务执行结束后,对数据进行解码、缩放和解压。处理完成后就进行回调。 - 通过重重回调,要回调的数据沿着
SDWebImageDownloaderOperation
->SDWebImageDownloader
->SDWebImageManager
->UIView+WebCache
一路流动,其中流动到SDWebImageManager
中时对图片进行了缓存,最后在UIView+WebCache
中为UIImageView
设置了处理好的图片。
源码分析
架构图
从SDWebImage中提供的架构图中我们可以大概的看出,整个库分为两层,Top Level、Base Module。
Top Level
:当UIImageView
调用加载image
方法,会进入SDWebImage
中的UIImageView
分类,在分类中调用负责加载UIImage
的核心代码块ImageManager
,其主要负责调度Image Cache/Image Loader
,这两者分别从缓存或者网络端加载图片,并且又进行了细分。Cache中获取图片业务,拆分到了memory/disk
两个分类中;Image Loader
中又分为从网络端获取或者从系统的Photos中获取。Base Module
:获取到图片的二进制数据处理,二进制解压缩,二进制中格式字节判断出具体的图片类型。
结构
(设计思路借鉴:提供多种接口,到底层调用到同一个方法,减少调用方对可选参数的传递)
UIImageView+WebCache
和UIButton+WebCache
直接为表层的 UIKit框架提供接口,SDWebImageManger
(SDWebImageManager
是SDWebImage
的核心类,也是我们经常接触到的类)负责处理和协调SDWebImageDownloader
和SDWebImageCache
, 并与UIKit层进行交互。SDWebImageDownloaderOperation
真正执行下载请求;SDWebImageCompat
是最基础的配置文件,为了兼容苹果各个平台SDWebImageDecoder
sd解码图片这个类其实是UIImage
的一个分类UIImage+ForceDecode
,主要用来解码UIImage
SDWebImageManager
SDWebImageManager是SDWebImage的核心类,也是我们经常接触到的类,我们将一起看下是如何实现的
1. SDWebImageOptions
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
/**
* By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
* This flag disable this blacklisting.
不会重新下载已经失败过的图片
*/
SDWebImageRetryFailed = 1 << 0,
/**
* By default, image downloads are started during UI interactions, this flags disable this feature,
* leading to delayed download on UIScrollView deceleration for instance.
*默认情况下,图像下载是在UI交互期间启动的,此标志禁用此功能,
*导致延迟下载UIScrollView减速为例。
*/
SDWebImageLowPriority = 1 << 1,
/**
* This flag disables on-disk caching
禁止在磁盘缓存,只在缓存中存在
*/
SDWebImageCacheMemoryOnly = 1 << 2,
/**
* This flag enables progressive download, the image is displayed progressively during download as a browser would do.
* By default, the image is only displayed once completely downloaded.
此标志支持逐行下载,图像在下载过程中逐步显示,就像浏览器所做的那样。
*默认情况下,图像只显示一次,完全下载。
*/
SDWebImageProgressiveDownload = 1 << 3,
/**
* Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
* The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
* This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
* If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
*
* Use this flag only if you can't make your URLs static with embedded cache busting parameter.
任何图片都从新下载,不使用http cache,比如一个图片发送变化,但是url没有变化,用改options刷新数据
*/
SDWebImageRefreshCached = 1 << 4,
/**
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
后台下载
*/
SDWebImageContinueInBackground = 1 << 5,
/**
* Handles cookies stored in NSHTTPCookieStore by setting
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
存储在cookie nshttpcookiestore
*/
SDWebImageHandleCookies = 1 << 6,
/**
* Enable to allow untrusted SSL certificates.
* Useful for testing purposes. Use with caution in production.
允许不信任的ssl证书
*/
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
/**
* By default, images are loaded in the order in which they were queued. This flag moves them to
* the front of the queue.
默认情况下,图像按它们排队的顺序加载。这个标志是将图片放在队列的最前面
*/
SDWebImageHighPriority = 1 << 8,
/**
* By default, placeholder images are loaded while the image is loading. This flag will delay the loading
* of the placeholder image until after the image has finished loading.
占位符图像是在图像加载时加载的,完全加载完才暂时
*/
SDWebImageDelayPlaceholder = 1 << 9,
/**
* We usually don't call transformDownloadedImage delegate method on animated images,
* as most transformation code would mangle it.
* Use this flag to transform them anyway.
转换图像
*/
SDWebImageTransformAnimatedImage = 1 << 10,
/**
* By default, image is added to the imageView after download. But in some cases, we want to
* have the hand before setting the image (apply a filter or add it with cross-fade animation for instance)
* Use this flag if you want to manually set the image in the completion when success
默认情况下,image是在下载完成后加载,但是在一些情况下,我们想要在设置图像之前使用(例如应用过滤器或添加交叉淡入淡出动画),如果您想在成功完成时手动设置图像,请使用此标志
*/
SDWebImageAvoidAutoSetImage = 1 << 11,
/**
* By default, images are decoded respecting their original size. On iOS, this flag will scale down the
* images to a size compatible with the constrained memory of devices.
* If `SDWebImageProgressiveDownload` flag is set the scale down is deactivated.
默认情况下,图像是进行解码的,这个标志是按比例缩小images的尺寸,来缩小占用的手机内存,如果` sdwebimageprogressivedownload `标志设置的情况下被停用。,压缩大的图片
*/
SDWebImageScaleDownLargeImages = 1 << 12
};
2. SDWebImageManagerDelegate
@protocol SDWebImageManagerDelegate <NSObject>
@optional
/**
* Controls which image should be downloaded when the image is not found in the cache.
*
* @param imageManager The current `SDWebImageManager`
* @param imageURL The url of the image to be downloaded
*
* @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
//当缓存没有发现当前图片,那么会查看调用者是否实现改方法,如果return一个no,则不会继续下载这张图片
*/
- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nullable NSURL *)imageURL;
/**
* Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
* NOTE: This method is called from a global queue in order to not to block the main thread.
*
* @param imageManager The current `SDWebImageManager`
* @param image The image to transform
* @param imageURL The url of the image to transform
*
* @return The transformed image object.
//当图片下载完成但是未添加到缓存里面,这时候调用该方法可以给图片旋转方向,注意是异步执行, 防止组织主线程
*/
- (nullable UIImage *)imageManager:(nonnull SDWebImageManager *)imageManager transformDownloadedImage:(nullable UIImage *)image withURL:(nullable NSURL *)imageURL;
@end
SDWebImageCompat
SDWebImage库中SDWebImageCompat是最基础的配置文件,为了兼容苹果各个平台。
SDWebImageCompat.h
#import <TargetConditionals.h>
//不支持OC的GC内存管理
#ifdef __OBJC_GC__
#error SDWebImage does not support Objective-C Garbage Collection
#endif
//苹果的`TargetConditionals.h`文件有点怪,在所有平台上TARGET_OS_MAC都被定义了,所以只能通过TARGET_OS_IPHONE=0这种方式进行判断
#if !TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH
#define SD_MAC 1
#else
#define SD_MAC 0
#endif
//判断是否支持UIKIT, iOS 与 tvOS都支持。
#if TARGET_OS_IOS || TARGET_OS_TV
#define SD_UIKIT 1
#else
#define SD_UIKIT 0
#endif
//是否是iOS系统
#if TARGET_OS_IOS
#define SD_IOS 1
#else
#define SD_IOS 0
#endif
//是否是TV系统
#if TARGET_OS_TV
#define SD_TV 1
#else
#define SD_TV 0
#endif
//是否是watchOS系统
#if TARGET_OS_WATCH
#define SD_WATCH 1
#else
#define SD_WATCH 0
#endif
#if SD_MAC
#import <AppKit/AppKit.h>
#ifndef UIImage
#define UIImage NSImage
#endif
#ifndef UIImageView
#define UIImageView NSImageView
#endif
#ifndef UIView
#define UIView NSView
#endif
#else
#if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
#error SDWebImage doesn't support Deployment Target version < 5.0
#endif
#if SD_UIKIT
#import <UIKit/UIKit.h>
#endif
#if SD_WATCH
#import <WatchKit/WatchKit.h>
#ifndef UIView
#define UIView WKInterfaceObject
#endif
#ifndef UIImageView
#define UIImageView WKInterfaceImage
#endif
#endif
#endif
#ifndef NS_ENUM
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#endif
#ifndef NS_OPTIONS
#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
#endif
FOUNDATION_EXPORT UIImage *SDScaledImageForKey(NSString *key, UIImage *image);
typedef void(^SDWebImageNoParamsBlock)(void);
FOUNDATION_EXPORT NSString *const SDWebImageErrorDomain;
#ifndef dispatch_queue_async_safe
#define dispatch_queue_async_safe(queue, block)\
if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(queue)) {\
block();\
} else {\
dispatch_async(queue, block);\
}
#endif
#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block) dispatch_queue_async_safe(dispatch_get_main_queue(), block)
#endif
SDWebImageCompat.m
#import "SDWebImageCompat.h"
#import "UIImage+MultiFormat.h"
//只能支持ARC
#if !__has_feature(objc_arc)
#error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
#endif
#if !OS_OBJECT_USE_OBJC
#error SDWebImage need ARC for dispatch object
#endif
//获取合适的scale的UIImage
inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) {
if (!image) {
return nil;
}
#if SD_MAC
return image;
#elif SD_UIKIT || SD_WATCH
if ((image.images).count > 0) {
NSMutableArray<UIImage *> *scaledImages = [NSMutableArray array];
for (UIImage *tempImage in image.images) {
[scaledImages addObject:SDScaledImageForKey(key, tempImage)];
}
UIImage *animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration];
if (animatedImage) {
animatedImage.sd_imageLoopCount = image.sd_imageLoopCount;
}
return animatedImage;
} else {
#if SD_WATCH
if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) {
#elif SD_UIKIT
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
#endif
CGFloat scale = 1;
if (key.length >= 8) {
NSRange range = [key rangeOfString:@"@2x."];
if (range.location != NSNotFound) {
scale = 2.0;
}
range = [key rangeOfString:@"@3x."];
if (range.location != NSNotFound) {
scale = 3.0;
}
}
UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
image = scaledImage;
}
return image;
}
#endif
}
NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain";
sd_imageIndicator
图片下载loading的indicator,主要是这两个方法,这个属性也是需要开发者自己去设置的
//对属性sd_imageIndicator 加载indicator添加关联对象
- (id<SDWebImageIndicator>)sd_imageIndicator {
return objc_getAssociatedObject(self, @selector(sd_imageIndicator));
}
- (void)setSd_imageIndicator:(id<SDWebImageIndicator>)sd_imageIndicator {
// 由于是之前添加了一个indicator,所以每次进来的时候
//都需要移除之前的indicator
id<SDWebImageIndicator> previousIndicator = self.sd_imageIndicator;
[previousIndicator.indicatorView removeFromSuperview];
//重新设置关联对象sd_imageIndicator
objc_setAssociatedObject(self, @selector(sd_imageIndicator), sd_imageIndicator, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//在当前UIImageView/UIButton中添加indicatorView
//这样就展示出indicatorView来了
UIView *view = sd_imageIndicator.indicatorView;
if (CGRectEqualToRect(view.frame, CGRectZero)) {
view.frame = self.bounds;
}
// Center the indicator view
#if SD_MAC
CGPoint center = CGPointMake(NSMidX(self.bounds), NSMidY(self.bounds));
NSRect frame = view.frame;
view.frame = NSMakeRect(center.x - NSMidX(frame), center.y - NSMidY(frame), NSWidth(frame), NSHeight(frame));
#else
//设置展示在当前的中心center位置
view.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
#endif
view.hidden = NO;
[self addSubview:view];
}
SDWebImage中已经为我们封装好了对应的类SDWebImageActivityIndicator,以及相应的方法,来实现对应的loading中的indicator效果只需要按照下面代码进行调用
//设置indicator方式为grayLargeIndicator,会显示一个大的灰色indicator
self.image.sd_imageIndicator = SDWebImageActivityIndicator.grayLargeIndicator
在SDWebImageActivityIndicator对应的分类中还有很多类型,下面是所有的类型
/// These indicator use the fixed color without dark mode support
/// gray-style activity indicator
@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayIndicator;
/// large gray-style activity indicator
@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *grayLargeIndicator;
/// white-style activity indicator
@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *whiteIndicator;
/// large white-style activity indicator
@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *whiteLargeIndicator;
/// These indicator use the system style, supports dark mode if available (iOS 13+/macOS 10.14+)
/// large activity indicator
@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *largeIndicator;
/// medium activity indicator
@property (nonatomic, class, nonnull, readonly) SDWebImageActivityIndicator *mediumIndicator;
UIImageView+WebCache层
面向UIImageView的是UIImageView+WebCache这个分类,将图片的URL,占位图片直接给这个类,下面是这个类的公共接口:
- (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context;
- (void)sd_setImageWithURL:(nullable NSURL *)url
completed:(nullable SDExternalCompletionBlock)completedBlock;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
其中这几个方法最终都会进入
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
SDWebImageOptions,设置的图片加载以及缓存策略,有几种类型
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
/**
默认情况下,当一个URL下载失败的时候,这个URL会被加入黑名单列表,
下次再有这个url的请求则停止请求。
如果为true,这个值表示需要再尝试请求。
*/
SDWebImageRetryFailed = 1 << 0,
/**
默认情况下,当UI可以交互的时候就开始加载图片。这个标记可以阻止这个时候加载。
而是当UIScrollView开始减速滑动的时候开始加载。
*/
SDWebImageLowPriority = 1 << 1,
/**
这个flag启动渐进式下载图像,类似浏览器加载图像那样逐步显示(从上倒下加载)
*/
SDWebImageProgressiveLoad = 1 << 2,
/**
一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDImageCache。即在URL没变但是服务器图片发生更新时使用,这时我们需要在NSMutableRequest中设置上(If-Modified-Since-其实是缓存的最后修改时间,有后台返回),这个参数是在上一次网络请求之后,NSResponse中的Last-Modified获取,并保存下载,在下次发送网络请求的时候添加到请求头中;这样当我们下载同一张照片的时候,其实是拿取的上次GET请求的NSURLCache缓存中的图片,并且如果后台发生变化会重新请求图片
*/
SDWebImageRefreshCached = 1 << 3,
/**
启动后台下载,实现原理是通过向系统询问后台的额外时间来完成请求的。 如果后台任务到期,则操作将被取消
*/
SDWebImageContinueInBackground = 1 << 4,
/**
当设置了NSMutableURLRequest.HTTPShouldHandleCookies = YES时,可以控制存储NSHTTPCookieStorage中的cookie
*/
SDWebImageHandleCookies = 1 << 5,
/**
允许不安全的SSL证书,用于测试环境,在正式环境中谨慎使用
*/
SDWebImageAllowInvalidSSLCertificates = 1 << 6,
/**
默认情况下,image在加载的时候是按照他们在队列中的顺序装载的(就是先进先出)。这个flag会把他们移动到队列的前端,并且立刻装载,而不是等到当前队列装载的时候再装载。
*/
SDWebImageHighPriority = 1 << 7,
/**
默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.
*/
SDWebImageDelayPlaceholder = 1 << 8,
/**
一般不会在动画图片上调用 transformDownloadedImage 代理方法,这样不能够管理动画图片
这个flag为尝试转换动画图片
*/
SDWebImageTransformAnimatedImage = 1 << 9,
/**
图片在下载后被加载到imageView。这个flag避免自动设置图片,来手动设置一下图片(引用一个滤镜或者加入透入动画)
*/
SDWebImageAvoidAutoSetImage = 1 << 10,
/**
默认情况下,图像将根据其原始大小进行解码。 在iOS上,此flat会将图片缩小到与设备的受限内存兼容的大小。 但如果设置了SDWebImageAvoidDecodeImage则此flat不起作用。 如果设置了SDWebImageProgressiveLoad它将被忽略
*/
SDWebImageScaleDownLargeImages = 1 << 11,
/**
结合SDWebImageQueryMemoryData设置同步查询图像数据(一般不建议这么使用,除非是在同一个runloop里避免单元格复用时发生闪现)
*/
SDWebImageQueryMemoryData = 1 << 12,
/**
结合SDWebImageQueryMemoryData设置同步查询图像数据(一般不建议这么使用,除非是在同一个runloop里避免单元格复用时发生闪现)
*/
SDWebImageQueryMemoryDataSync = 1 << 13,
/**
如果内存查询没有的时候,强制同步磁盘查询(这三个查询可以组合使用,一般不建议这么使用,除非是在同一个runloop里避免单元格复用时发生闪现)
*/
SDWebImageQueryDiskDataSync = 1 << 14,
/**
* 默认情况下,当缓存丢失时,SD将从网络下载图像。 此flat可以防止这样,使其仅从缓存加载。
*/
SDWebImageFromCacheOnly = 1 << 15,
/**
* 默认情况下,SD在下载之前先从缓存中查找,此flat可以防止这样,使其仅从网络下载
*/
SDWebImageFromLoaderOnly = 1 << 16,
/**
* 默认情况下,SD在图像加载完成后使用SDWebImageTransition进行某些视图转换,此转换仅适用于从网络下载图像。 此flat可以强制为内存和磁盘缓存应用视图转换。
*/
SDWebImageForceTransition = 1 << 17,
/**
默认情况下,SD在查询缓存和从网络下载时会在后台解码图像,这有助于提高性能,因为在屏幕上渲染图像时,需要首先对其进行解码。这发生在Core Animation的主队列中。然而此过程也可能会增加内存使用量。
如果由于过多的内存消耗而遇到问题,可以用此flat禁止解码图像。
*/
SDWebImageAvoidDecodeImage = 1 << 18,
/**
* 默认情况下,SD会解码动画图像,该flat强制只解码第一帧并生成静态图。
*/
SDWebImageDecodeFirstFrameOnly = 1 << 19,
/**
默认情况下,对于SDAnimatedImage,SD会在渲染过程中解码动画图像帧以减少内存使用量。 但是用户可以指定将所有帧预加载到内存中,以便在大量imageView共享动画图像时降低CPU使用率。这实际上会在后台队列中触发preloadAllAnimatedImageFrames(仅限磁盘缓存和下载)。
*/
SDWebImagePreloadAllFrames = 1 << 20
};
还有一个变量是SDWebImageContext *context
,可以看到SDWebImageContext
其实就是以 SDWebImageContextOption
为key
、id
(指定类型或者协议)为value
的NSDictionary