参考:http://blog.youkuaiyun.com/benyoulai5/article/details/50462586
http://www.jianshu.com/p/7a2aab8553fe
https://www.jianshu.com/p/7dea5b081d24
让sdwebimage不缓存图片,每次都重新加载url:https://blog.youkuaiyun.com/feiyuyuan_9257/article/details/77717343
[imageview sd_setImageWithURL:url placeholderImage:image options:SDWebImageRefreshCached completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
}];
viewdidload 或init方法里面加入-(void)sdWEbDownloaderRegister{
SDWebImageDownloader *imgDownloader = SDWebImageManager.sharedManager.imageDownloader;
imgDownloader.headersFilter = ^NSDictionary *(NSURL *url, NSDictionary *headers) {
NSFileManager *fm = [[NSFileManager alloc] init];
NSString *imgKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
NSString *imgPath = [SDWebImageManager.sharedManager.imageCache defaultCachePathForKey:imgKey];
NSDictionary *fileAttr = [fm attributesOfItemAtPath:imgPath error:nil];
NSMutableDictionary *mutableHeaders = [headers mutableCopy];
NSDate *lastModifiedDate = nil;
if (fileAttr.count > 0) {
if (fileAttr.count > 0) {
lastModifiedDate = (NSDate *)fileAttr[NSFileModificationDate];
}
}
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
formatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss z";
NSString *lastModifiedStr = [formatter stringFromDate:lastModifiedDate];
lastModifiedStr = lastModifiedStr.length > 0 ? lastModifiedStr : @"";
[mutableHeaders setValue:lastModifiedStr forKey:@"If-Modified-Since"];
return mutableHeaders;
};
}
SDWebImage 概论
1.提供了一个UIImageView的category用来加载网络图片并且对网络图片的缓存进行管理
2.采用异步方式来下载网络图片
3.采用异步方式,使用memory+disk来缓存网络图片,自动管理缓存。
4.支持GIF动画
5.支持WebP格式
6.同一个URL的网络图片不会被重复下载
7.失效的URL不会被无限重试
8.耗时操作都在子线程,确保不会阻塞主线程
9.使用GCD和ARC
10.支持Arm64
SDWebImage 使用
1.使用IImageView+WebCache category来加载UITableView中cell的图片
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
2.使用Blocks,采用这个方案可以在网络图片加载过程中得知图片的下载进度和图片加载成功与否
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"] completed:^(UIImage image, NSError error, SDImageCacheType cacheType, NSURL *imageURL) { ... completion code here ... }];
3.使用SDWebImageManager,SDWebImageManager为UIImageView+WebCache category的实现提供接口。
SDWebImageManager manager = [SDWebImageManager sharedManager] ;[manager downloadImageWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) { // progression tracking code } completed:^(UIImage image, NSError error, SDImageCacheType cacheType, BOOL finished, NSURL imageURL) { if (image) { // do something with image } }];
4.加载图片还有使用SDWebImageDownloader和SDImageCache方式,但那个并不是我们经常用到的。基本上面所讲的3个方法都能满足需求。
SDWebImage 流程
几个常用接口:
-
获取SDWebImage的磁盘缓存大小,在项目中有时候会需要统计应用的磁盘缓存内容大小,那么获取图片的缓存大小就是使用这个接口来实现
[SDImageCache sharedImageCache] getSize];
-
清理内存缓存,清理内存中缓存的图片资源,释放内存资源。
[[SDImageCache sharedImageCache] clearMemory];
-
有了清理内存缓存,自然也有清理磁盘缓存的接口
[[SDImageCache sharedImageCache] clearDisk];
//////////////////////////////
#import "ViewController.h"
#import "UIImageView+WebCache.h"
#import "SDWebImageManager.h"
#import "SDWebImageDownloader.h"
#import "UIImage+GIF.h"
#import "NSData+ImageContentType.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self download];
}
//1.下载图片且需要获取下载进度
/**
* 1:当需要获取下载进度的时候可以使用此方法,其中optiobs如果什么都不做,可以传参数0,optiobs是一个位移枚举,可以通过按位或 | 来并列添加参数 2:SDImageCacheType缓存的类型:此方法默认做了内存缓存,与磁盘缓存,第一次是直接下载,然后点击的时候是从内存缓存中读取,当内存缓存不存在的时候,再从磁盘缓存读取
*
*/
//内存缓存&磁盘缓存
-(void)download
{
[self.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://img4.duitang.com/uploads/blog/201310/18/20131018213446_smUw4.thumb.600_0.jpeg"] placeholderImage:[UIImage imageNamed:@"Snip20160221_306"] options:SDWebImageCacheMemoryOnly | SDWebImageProgressiveDownload progress:^(NSInteger receivedSize, NSInteger expectedSize) {
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
switch (cacheType) {
case SDImageCacheTypeNone:
NSLog(@"直接下载");
break;
case SDImageCacheTypeDisk:
NSLog(@"磁盘缓存");
break;
case SDImageCacheTypeMemory:
NSLog(@"内存缓存");
break;
default:
break;
}
}];
NSLog(@"%@",[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]);
}
//2.只需要简单获得一张图片,不设置
/**
* 1:默认SDImageCacheType是内存缓存&磁盘缓存。如果只是简单下载一张图片,就用如下的方法:[SDWebImageManager sharedManager] downloadImageWithURL
*
*/
-(void)download2
{
[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:@"http://img4.duitang.com/uploads/blog/201310/18/20131018213446_smUw4.thumb.600_0.jpeg"] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {
NSLog(@"%f",1.0 * receivedSize / expectedSize);
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
//得到图片
self.imageView.image = image;
}];
}
//3.不需要任何的缓存处理
/**
* 没有做任何缓存处理
*
*/
-(void)download3
{
//data:图片的二进制数据
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:@"http://img4.duitang.com/uploads/blog/201310/18/20131018213446_smUw4.thumb.600_0.jpeg"] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {
} completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
}
//4.播放Gif图片
/**
*播放Gif图片
*/
-(void)gif
{
NSLog(@"%s",__func__);
//self.imageView.image = [UIImage imageNamed:@"39e805d5ad6eddc4f80259d23bdbb6fd536633ca"];
UIImage *image = [UIImage sd_animatedGIFNamed:@"39e805d5ad6eddc4f80259d23bdbb6fd536633ca"];
self.imageView.image = image;
}
-(void)type
{
NSData *imageData = [NSData dataWithContentsOfFile:@"/Users/xiaomage/Desktop/Snip20160221_306.png"];
NSString *typeStr = [NSData sd_contentTypeForImageData:imageData];
NSLog(@"%@",typeStr);
}
@end
二:当内存产生警告的时候,清除缓存
#import "AppDelegate.h"
#import "SDWebImageManager.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
//1.清空缓存
//clear:直接删除缓存目录下面的文件,然后重新创建空的缓存文件
//clean:清除过期缓存,计算当前缓存的大小,和设置的最大缓存数量比较,如果超出那么会继续删除(按照文件了创建的先后顺序)
//过期时间:7天
[[SDWebImageManager sharedManager].imageCache clearMemory];
//2.取消当前所有的操作
[[SDWebImageManager sharedManager] cancelAll];
//3.最大并发数量 == 6
//4.缓存文件的保存名称如何处理? 拿到图片的URL路径,对该路径进行MD5加密
//5.该框架内部对内存警告的处理方式? 内部通过监听通知的方式请你缓存
//6.该框架进行缓存处理的方式:可变字典--->NSCache
//7.如何判断图片的类型: 在判断图片类型的时候,只匹配第一个字节
//8.队列中任务的处理方式:FIFO
//9.如何下载图片的? 发送网络请求下载图片,NSURLConnection
//10.请求超时的时间 15秒
//[NSData dataWithContentsOfURL:<#(nonnull NSURL *)#>]
}
@end
三:SDWebImage的结构:最顶层的父类是SDWebImageManager,其下有两个子类如图所示
四:知识点总结:
01 设置imageView的图片
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"placehoder"]]; 02 设置图片并计算下载进度 //下载并设置图片 /* 第一个参数:要下载图片的url地址 第二个参数:设置该imageView的占位图片 第三个参数:传一个枚举值,告诉程序你下载图片的策略是什么 第一个block块:获取当前图片数据的下载进度 receivedSize:已经下载完成的数据大小 expectedSize:该文件的数据总大小 第二个block块:当图片下载完成之后执行该block中的代码 image:下载得到的图片数据 error:下载出现的错误信息 SDImageCacheType:图片的缓存策略(不缓存,内存缓存,沙盒缓存) imageURL:下载的图片的url地址 */ [cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"placehoder"] options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) { //计算当前图片的下载进度 NSLog(@"%.2f",1.0 *receivedSize / expectedSize); } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { }]; 03 系统级内存警告如何处理(面试) //取消当前正在进行的所有下载操作 [[SDWebImageManager sharedManager] cancelAll]; //清除缓存数据(面试) //cleanDisk:删除过期的文件数据,计算当前未过期的已经下载的文件数据的大小,如果发现该数据大小大于我们设置的最大缓存数据大小,那么程序内部会按照按文件数据缓存的时间从远到近删除,知道小于最大缓存数据为止。 //clearMemory:直接删除文件,重新创建新的文件夹 //[[SDWebImageManager sharedManager].imageCache cleanDisk]; [[SDWebImageManager sharedManager].imageCache clearMemory]; 04 SDWebImage默认的缓存时间是1周 05 如何播放gif图片 /* 5-1 把用户传入的gif图片->NSData 5-2 根据该Data创建一个图片数据源(NSData->CFImageSourceRef) 5-3 计算该数据源中一共有多少帧,把每一帧数据取出来放到图片数组中 5-4 根据得到的数组+计算的动画时间-》可动画的image [UIImage animatedImageWithImages:images duration:duration]; */ 06 如何判断当前图片类型,只判断图片二进制数据的第一个字节 + (NSString *)sd_contentTypeForImageData:(NSData *)data; 07 内部如何进行缓存处理?使用了NSCache类,使用和NSDictionary类似 08 沙盒缓存图片的命名方式为对该图片的URL进行MD5加密 echo -n "url" |MD5 09 当接收到内存警告之后,内部会自动清理内存缓存 10 图片的下载顺序,默认是先进先出的:FIFO原则
********新版的sdwebimage找不到 sd_animatedGIFWithData方法,需要自己查创建,
UIImage * image = [self sd_animatedGIFWithData:data];
//新版的sdwebimage没有下面的方法
-(UIImage *)sd_animatedGIFWithData:(NSData *)data {
if (!data) {
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
size_t count = CGImageSourceGetCount(source);
UIImage *animatedImage;
if (count <= 1) {
animatedImage = [[UIImage alloc] initWithData:data];
}
else {
NSMutableArray *images = [NSMutableArray array];
NSTimeInterval duration = 0.0f;
for (size_t i = 0; i < count; i++) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
duration += [self sd_frameDurationAtIndex:i source:source];
[images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
CGImageRelease(image);
}
if (!duration) {
duration = (1.0f / 10.0f) * count;
}
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
}
CFRelease(source);
return animatedImage;
}
-(float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
float frameDuration = 0.1f;
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
}
else {
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
}
}
if (frameDuration < 0.011f) {
frameDuration = 0.100f;
}
CFRelease(cfFrameProperties);
return frameDuration;
}