SDWebImage源码探究(四)
UIImageView+normal 下载图片
这个应该是SDWebImage的最基本的使用了,就是利用给定的URL下载图片,采用的是UIImageView的分类webcache.
代码:
#import "JJWebImageVC.h" #import "Masonry.h" #import "UIImageView+WebCache.h" @interface JJWebImageVC () @property (nonatomic, strong) UIImageView *imageView; @end @implementation JJWebImageVC #pragma mark - Override Base Function - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor lightGrayColor]; [self setupUI]; [self loadData]; } #pragma mark - Object Private Function - (void)setupUI { UIImageView *imageView = [[UIImageView alloc] init]; [self.view addSubview:imageView]; self.imageView = imageView; [imageView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.view); make.height.width.equalTo(@200); }]; } - (void)loadData { [self.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://picture.51rebo.cn/149991503036592"] placeholderImage:[UIImage imageNamed:@"placeholder"]]; } @end
图片下载除了上面这个方法还有下面几个方法
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options; - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock; - (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 SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock;
这里最后面这个方法的参数是最多的,达到了5个,多的不说了,主要说一下progress这个是下载进度的回调,completed下载完成的block,options这个参数是最重要的,是一个枚举值,主要对下载图片的情况进行配置,下面我们就看一下这个枚举值。
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. */ //默认的情况下,当一个URL下载失败了,那么这个URL会被放在黑名单里面,不会继续尝试,这个标志位就是使黑名单效果失效,保证失败后可以重新尝试。 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. */ //刷新缓存 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; */ //处理NSHTTPCookieStore中存储的cookie 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. */ //我们一般不调用transformDownloadedImage代理方法处理动画图片,因为大多数的转换代码会损坏它,使用这个标志位可以转换它们。 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 */ //默认情况下,图像在下载完成后都是加载到UIImageview上,但是在一些情况下,我们想要在设置图像之前处理它,比如说加一个滤镜或者褪色的动画效果等等,使用这个标志位,如果你想要手动的在成功完成回调后设置这个图片。 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. */ //默认情况下,图像都是根据他们原始尺寸进行解码,在ios中,这个标志位会缩小图片,以便能够兼容器件内存的限制,如果SDWebImageProgressiveDownload被设置了,那么这个位就失效了。 SDWebImageScaleDownLargeImages = 1 << 12 };
UIImageView+highlightedImage图片下载
这个方法也是UIImageView的分类,专门用来下载highlightedImage。调用的是下面这个方法。
- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock;
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options operationKey:(nullable NSString *)operationKey setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock;
判断是否是gif图
这个要根据UIImage的一个分类UIImage+GIF进行判断。UIImage对象有一个属性如下:
@property(nullable, nonatomic,readonly) NSArray<UIImage *> *images NS_AVAILABLE_IOS(5_0); // default is nil for non-animated images
根据NSData创建动画的图像
这个方法也在分类UIImage+GIF里面,如下所示。
/** * Compatibility method - creates an animated UIImage from an NSData, it will only contain the 1st frame image */ + (UIImage *)sd_animatedGIFWithData:(NSData *)data;
UIButton设置图像
该框架也提供了UIButton设置图像的方法,以及设置背景图像的方法,还有就是取消的方法,下面我们接着看。
1.设置图像的方法
#pragma mark - Image /** * Get the image URL for a control state. * * @param state Which state you want to know the URL for. The values are described in UIControlState. */ - (nullable NSURL *)sd_imageURLForState:(UIControlState)state; /** * Set the imageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state; /** * Set the imageView `image` with an `url` and a placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @see sd_setImageWithURL:placeholderImage:options: */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder; /** * Set the imageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options; /** * Set the imageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock;
2.获取按钮图像的URL
/** * Get the current image URL. */ - (nullable NSURL *)sd_currentImageURL;
3、获取按钮背景backgroundImage
#pragma mark - Background image /** * Set the backgroundImageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state; /** * Set the backgroundImageView `image` with an `url` and a placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @see sd_setImageWithURL:placeholderImage:options: */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder; /** * Set the backgroundImageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options; /** * Set the backgroundImageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the backgroundImageView `image` with an `url`, placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the backgroundImageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock;
4、按钮下载图片的取消方法
/** * Cancel the current image download //取消图片下载 */ - (void)sd_cancelImageLoadForState:(UIControlState)state; /** * Cancel the current backgroundImage download //取消背景图片的下载 */ - (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state;
判断获取图片的格式
我们根据NSdata获取图片,有的时候需要知道获取图片的格式,分类NSData+ImageContentType就很好的解决了这个问题,我们先看这个方法。
typedef NS_ENUM(NSInteger, SDImageFormat) { SDImageFormatUndefined = -1, SDImageFormatJPEG = 0, SDImageFormatPNG, SDImageFormatGIF, SDImageFormatTIFF, SDImageFormatWebP }; @interface NSData (ImageContentType) /** * Return image format * * @param data the input image data * * @return the image format as `SDImageFormat` (enum) */ + (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data; @end
它的返回值是一个枚举,会返回6中类型,其中一个是未定义类型,下面我们就研究下该方法是如何实现的。
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data { if (!data) { return SDImageFormatUndefined; } uint8_t c; [data getBytes:&c length:1]; switch (c) { case 0xFF: return SDImageFormatJPEG; case 0x89: return SDImageFormatPNG; case 0x47: return SDImageFormatGIF; case 0x49: case 0x4D: return SDImageFormatTIFF; case 0x52: // R as RIFF for WEBP if (data.length < 12) { return SDImageFormatUndefined; } NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { return SDImageFormatWebP; } } return SDImageFormatUndefined; }
缓存图像
缓存图像这里就包括缓存到disk和memory两种情况。涉及到的类主要就是SDImageCache。下面四中方法都是缓存图像到内存和硬盘,前三种方法都是异步存储,后面一种方法是同步存储。
#pragma mark - Store Ops /** * Asynchronously store an image into memory and disk cache at the given key. //异步存储指定key对应的图片到内存和disk * * @param image The image to store * @param key The unique image cache key, usually it's image absolute URL * @param completionBlock A block executed after the operation is finished */ - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key completion:(nullable SDWebImageNoParamsBlock)completionBlock; /** * Asynchronously store an image into memory and disk cache at the given key. //异步存储指定key对应的图片到内存和disk * * @param image The image to store * @param key The unique image cache key, usually it's image absolute URL * @param toDisk Store the image to disk cache if YES * @param completionBlock A block executed after the operation is finished */ - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock; /** * Asynchronously store an image into memory and disk cache at the given key. //异步存储指定key对应的图片到内存和disk * * @param image The image to store * @param imageData The image data as returned by the server, this representation will be used for disk storage * instead of converting the given image object into a storable/compressed image format in order * to save quality and CPU * @param key The unique image cache key, usually it's image absolute URL * @param toDisk Store the image to disk cache if YES * @param completionBlock A block executed after the operation is finished */ - (void)storeImage:(nullable UIImage *)image imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock; /** * Synchronously store image NSData into disk cache at the given key. //同步存储指定key对应的NSData对象到disk * * @warning This method is synchronous, make sure to call it from the ioQueue * * @param imageData The image data to store * @param key The unique image cache key, usually it's image absolute URL */ - (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key;