版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.07.15 |
前言
我们做APP,文字和图片是绝对不可缺少的元素,特别是图片一般存储在图床里面,一般公司可以委托第三方保存,NB的公司也可以自己存储图片,ios有很多图片加载的第三方框架,其中最优秀的莫过于SDWebImage,它几乎可以满足你所有的需求,用了好几年这个框架,今天想总结一下。感兴趣的可以看其他几篇。
1. SDWebImage探究(一)
2. SDWebImage探究(二)
3. SDWebImage探究(三)
这一篇主要说一下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
运行起来,刚要加载图片发现一个警告。
2017-07-15 15:43:58.940 JJWebImage[1507:30761] App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
这个是apple为了网络安全进行的https协议,想要用http协议只需要配置一下info.plist文件即可。这个方法很好解决了,就是增加一个键值对就可以,最后在说一下吧,如下,自己看图。
除了用这个方法,还可以用下面几个方法。
- (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;
参数说明和下载流程和normal是一样的,就不多说了。最后都是调用UIView+WebCache.h
里的下面方法进行下载展示。
- (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
这个属性的意思是,对于非动画的图像,默认为nil。所以判断方法如下:
- (BOOL)isGIF
{
return (self.images != nil);
}
根据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;
这个方法会根据NSData创建一个动画图像,仅仅包含第一真的图像。下面我们看一下是如何实现的。
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data
{
if (!data) {
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
size_t count = CGImageSourceGetCount(source);
UIImage *staticImage;
if (count <= 1) {
staticImage = [[UIImage alloc] initWithData:data];
} else {
// we will only retrieve the 1st frame. the full GIF support is available via the FLAnimatedImageView category.
// this here is only code to allow drawing animated images as static ones
#if SD_WATCH
CGFloat scale = 1;
scale = [WKInterfaceDevice currentDevice].screenScale;
#elif SD_UIKIT
CGFloat scale = 1;
scale = [UIScreen mainScreen].scale;
#endif
CGImageRef CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL);
#if SD_UIKIT || SD_WATCH
UIImage *frameImage = [UIImage imageWithCGImage:CGImage scale:scale orientation:UIImageOrientationUp];
staticImage = [UIImage animatedImageWithImages:@[frameImage] duration:0.0f];
#elif SD_MAC
staticImage = [[UIImage alloc] initWithCGImage:CGImage size:NSZeroSize];
#endif
CGImageRelease(CGImage);
}
CFRelease(source);
return staticImage;
}
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;
参数说明和使用方法和UIImageView + Webcache
是类似的,就不多说了。
2.获取按钮图像的URL
这个方法就是获取该按钮图像的URL地址的方法,如下:
/**
* Get the current image URL.
*/
- (nullable NSURL *)sd_currentImageURL;
3. 获取按钮背景backgroundImage
这个方法和按钮图像的方法其实是类似的,这个只是在下载完成后赋值给了button的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;
后记
未完,待续