原文出处:Yasin的简书 http://www.jianshu.com/p/b1045c3fc8d0

图片在APP中占有重要的角色,对图片做好缓存是重要的一项工作。
[TOC]

理论

不喜欢理论的可以直接跳到下面的Demo实践部分

缓存介绍

缓存按照保存位置可以分为两类:内存缓存、硬盘缓存(FMDB、CoreData...)。
我们常说的数据缓存包含内存缓存、硬盘缓存和网络请求URL缓存。其中网络请求URL缓存也包含内存缓存和硬盘缓存。

图片缓存思路

URL缓存(缓存请求)

网络请求除了客户端需要做简单的配置外,最主要需要服务器支持,服务端也很简单,只需要在response里面设置Cache-Control字段就行了.

最常见的URL缓存实现方式:NSURLCache。NSURLCache可以在memory 和 disk 上缓存。
AFNetWorking是基于NSURLSession(iOS7以上的网络请求框架),在生成配置的时候有三种配置选择

1 + (NSURLSessionConfiguration *)defaultSessionConfiguration;
2 //默认会话模式(default):工作模式类似于原来的NSURLConnection,使用的是基于磁盘缓存的持久化策略,使用用户keychain中保存的证书进行认证授权。
3 + (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
4 //瞬时会话模式(ephemeral):该模式不使用磁盘保存任何数据。所有和会话相关的caches,证书,cookies等都被保存在RAM中,因此当程序使会话无效,这些缓存的数据就会被自动清空。
5 + (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier;
6 //后台会话模式(background):该模式在后台完成上传和下载,在创建Configuration对象的时候需要提供一个NSString类型的ID用于标识完成工作的后台会话。

也就是说default同时实现了内存缓存和硬盘缓存,ephemeral实现了内存缓存,对于图片下载我们当然选择default。
我们还可以对缓存的大小进行设置,只需要对NSURLCache进行初始化就可以了

实现初始化

-application:didFinishLaunchingWithOptions:中对[NSURLCache sharedURLCache]进行初始化设置:

1 NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
2                                                          diskCapacity:20 * 1024 * 1024
3                                                              diskPath:nil];
4 [NSURLCache setSharedURLCache:URLCache];

也可以单独对NSURLSessionconfiguration进行设置,
在AFNetWorking中对于图片网络请求设置了20M的内存缓存和150M的硬盘缓存:

1 + (NSURLCache *)defaultURLCache {
2     return [[NSURLCache alloc] initWithMemoryCapacity:20 * 1024 * 1024
3                                          diskCapacity:150 * 1024 * 1024
4                                              diskPath:@"com.alamofire.imagedownloader"];
5 }

缓存策略

缓存策略是指对网络请求缓存如果处理,是使用缓存还是不使用

 1 NSURLRequestUseProtocolCachePolicy: 对特定的 URL 请求使用网络协议中实现的缓存逻辑。这是默认的策略。
 2 NSURLRequestReloadIgnoringLocalCacheData:数据需要从原始地址加载。不使用现有缓存。
 3 NSURLRequestReloadIgnoringLocalAndRemoteCacheData:不仅忽略本地缓存,
 4       同时也忽略代理服务器或其他中间介质目前已有的、协议允许的缓存。
 5 NSURLRequestReturnCacheDataElseLoad:无论缓存是否过期,先使用本地缓存数据。
 6       如果缓存中没有请求所对应的数据,那么从原始地址加载数据。
 7 NSURLRequestReturnCacheDataDontLoad:无论缓存是否过期,先使用本地缓存数据。
 8       如果缓存中没有请求所对应的数据,那么放弃从原始地址加载数据,
 9       请求视为失败(即:“离线”模式)。
10 NSURLRequestReloadRevalidatingCacheData:从原始地址确认缓存数据的合法性后,
11       缓存数据就可以使用,否则从原始地址加载。

在AFNetWorking中同样对configuration进行设置

1 configuration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;

如果你继承AFImageDownloader重新实现了他的初始化,requestCachePolicy注意AFImageDownloader中只有三种才设置了缓存

1 case NSURLRequestUseProtocolCachePolicy:
2 case NSURLRequestReturnCacheDataElseLoad:
3 case NSURLRequestReturnCacheDataDontLoad:

图片内存缓存

AFNetWorking3.0放弃了NSCache作为图片内存缓存管理,这让我非常不解。
有人说它的性能和 key 的相似度有关,如果有大量相似的 key (比如 "1", "2", "3", ...),NSCache 的存取性能会下降得非常厉害,大量的时间被消耗在 CFStringEqual() 上,不知这是不是放弃使用NSCache的原因。

像素在内存中的布局和它在磁盘中的存储方式并不相同。考虑一种简单的情况:每个像素有R、G、B和alpha四个值,每个值占用1字节,因此每个像素占用4字节的内存空间。一张1920*1080的照片(iPhone6 Plus的分辨率)一共有2,073,600个像素,因此占用了超过8Mb的内存。但是一张同样分辨率的PNG格式或JPEG格式的图片一般情况下不会有这么大。这是因为JPEG将像素数据进行了一种非常复杂且可逆的转化。

AFNetWorking3.0的图片缓存类貌似是基于这个理论来做内存大小管理的(之前AF的内存大小计算方法有错,我修改了一下提交了,现在已经审核通过合并进去了,哈哈哈哈哈,我也算是贡献过AF了)。AFNetWorking2.x中还是使用AFImageCache进行memory上缓存。

NSCache在memory上缓存,类似于NSMutableDictionary ,以 哈希算法 管理。有自动清理机制,当缓存到memory时,如果memory空间不够,则会自动删除memory中当前界面不使用的空间。

AFAutoPurgingImageCache使用NSMutableDictionary <NSString* , AFCachedImage*>进行内存缓存映射,并进行管理,当内存警告时就清空NSMutableDictionary。如果内存占用超过限制,则按照时间顺序进行删除。

图片硬盘缓存

就是我们常说的把数据保存在本地,比如FMDB、CoreData、归档、NSUserDefaults、NSFileManager等等,这里就不多说了。
AFNetWorking3.0没有直接做图片硬盘缓存,而是通过URL缓存做的硬盘缓存。也就是说,如果内存缓存没有读取到图片,就会调用下载逻辑,通过下载缓存的内存缓存硬盘缓存来获取到已下载过的图片,如果没有下载过,就会重新下载。
如果我们自己做图片硬盘缓存建议使用NSFileManager,因为一般图片data会比较大,测试证明路径缓存会比放在数据库有更高的性能。

实践

Demo下载

使用NSURLSession做网络请求缓存。

 1 NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];     //使用default配置,自带网络请求缓存
 2     [config setHTTPAdditionalHeaders:@{@"Accept":@"image/*"}];//设置网络数据格式
 3     NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
 4     NSURLRequest *request = [NSURLRequest requestWithURL:url];
 5     WEAKSELF
 6     NSURLSessionDataTask *task = [session dataTaskWithRequest:request
 7       completionHandler:^(NSData * _Nullable data,
 8     NSURLResponse * _Nullable response, NSError * _Nullable error) {
 9     //使用’获取数据(NSURLSessionDataTask)‘的方式发起请求
10         UIImage *image = [UIImage imageWithData:data];
11         dispatch_async(dispatch_get_main_queue(), ^{
12             weakSelf.imageView.image = image;
13         });
14     }];
15     [task resume];

我们通过连续两次下载图片可以发现defaultSessionConfiguration下NSURLSession会自动做网络请求缓存。

使用AFNetWorking下载图片

导入头文件#import "UIImageView+AFNetworking.h"
使用特别简单,只有一行代码:[imageView setImageWithURL:url];
UIImageView+AFNetworking做了内存缓存和基于NSURLSession的网络请求缓存,并没有做硬盘缓存,估计是考虑到图片的网络请求硬盘缓存足以满足需要,所以省略了额外的硬盘缓存,内存缓存加快了读取速度,这个是非常有必要的。

进入UIImageView+AFNetworking代码分析:

1 if ([urlRequest URL] == nil) {
2         [self cancelImageDownloadTask];
3         self.image = placeholderImage;
4         return;
5     }
6 //如果新传入的URL为空则取消图片下载并设置图片为默认图

1 if ([self isActiveTaskURLEqualToURLRequest:urlRequest]){
2         return;
3     }
4 //如果新传入的URL与当前URL相同则直接返回,否则取消当前下载,重新进行图片查找下载

UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
//从内存缓存中读取image,如果没有则发起新的请求

1 AFImageDownloader *downloader = [[self class] sharedImageDownloader];
2 //使用单例下载,内存缓存为downloader.imageCache
3 //downloader设置的网络请求20M的内存缓存和150M的硬盘缓存
4 //downloader设置的网络请求缓存策略为NSURLRequestUseProtocolCachePolicy
5 //imageCache设置了内存60M最大100M
6 //网络请求发起前会再次判断imageCache中是否含有该image

测试

使用Charles查看图片下载的网络请求发生了几次,判断缓存是否成功。
其中硬盘缓存需要写入时间,网络请求完成后略等一下,否则硬盘缓存不会生效

设置默认网络缓存大小

如果没有对NSURLRequestURLCache进行设置,默认是使用[NSURLCache sharedURLCache],所以如果有需要可以如下设置

 1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 2     // Override point for customization after application launch.
 3     [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
 4     //网络请求时状态栏网络状态小转轮
 5
 6     NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
 7                                                          diskCapacity:20 * 1024 * 1024
 8                                                              diskPath:nil];
 9     //内存4M,硬盘20M
10     [NSURLCache setSharedURLCache:URLCache];
11
12     return YES;
13 }

文/Yasin的简书(简书作者)
原文链接:http://www.jianshu.com/p/b1045c3fc8d0
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

转载于:https://www.cnblogs.com/iOSClub/p/5468027.html

【转载】基于AFNetWorking3.0的图片缓存分析相关推荐

  1. iOS开发--基于AFNetWorking3.0的图片缓存分析

    图片在APP中占有重要的角色,对图片做好缓存是重要的一项工作.[TOC] 理论 不喜欢理论的可以直接跳到下面的Demo实践部分 缓存介绍 缓存按照保存位置可以分为两类:内存缓存.硬盘缓存(FMDB.C ...

  2. 基于AFNetworking3.0网络封装

    概述 对于开发人员来说,学习网络层知识是必备的,任何一款App的开发,都需要到网络请求接口.很多朋友都还在使用原生的NSURLConnection一行一行地写,代码到处是,这样维护起来更困难了. 对于 ...

  3. think php上传图片,基于ThinkPHP5.0实现图片上传插件

    这篇文章主要介绍了关于基于ThinkPHP5.0实现图片上传插件,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 thinkphp5.0 图片上传插件可预览裁剪图片和保存原图片,执行裁剪 ...

  4. load方法引入本地html报错,分享基于plus.downloader的图片懒加载功能,支持本地缓存v1.1.0...

    今天试用了下hello mui上的图片懒加载功能,发现有些地方还无法满足我的需求,ajax动态加载的时候无法实现懒加载. 然后又看了下36kr的示例,因为代码关系实在太多了,耦合度比较高,遂自己动手写 ...

  5. 基于VUE2.0的高仿饿了么分析与总结

    2019独角兽企业重金招聘Python工程师标准>>> 首先,慕课网提供的视频是基于vue1.0的规范写的,因此有一些地方在vue2.0下不能正常运行.虽然课程补充文件也提供了vue ...

  6. mPaaS 3.0 多媒体组件发布 | 支付宝百亿级图片组件 xMedia 锤炼之路 (图片缓存篇)...

    一. 背景介绍 图片加载一直是 Android App 面临的"老大难"问题,加载速度与内存消耗天生就是一个矛盾统一体.我们依托支付宝超级 App 复杂的生态业务场景,借鉴业界领先 ...

  7. mPaaS 3.0 多媒体组件发布 | 支付宝百亿级图片组件 xMedia 锤炼之路 (图片缓存篇)... 1

    一. 背景介绍 图片加载一直是 Android App 面临的"老大难"问题,加载速度与内存消耗天生就是一个矛盾统一体.我们依托支付宝超级 App 复杂的生态业务场景,借鉴业界领先 ...

  8. RNA 29. SCI文章中基于TCGA的免疫浸润细胞分析 (TIMER2.0)

    桓峰基因公众号推出转录组分析教程,有需要生信的老师可以联系我们!转录分析教程整理如下: RNA 1. 基因表达那些事--基于 GEO RNA 2. SCI文章中基于GEO的差异表达基因之 limma ...

  9. Android的图片缓存ImageCache(转)

    为什么要做缓存?       在UI界面加载一张图片时很简单,然而如果需要加载多张较大的图像,事情就会变得更加复杂.在许多情况下(如ListView.GridView或ViewPager等的组件),屏 ...

最新文章

  1. 如何制作一个类似Tiny Wings的游戏 Cocos2d-x 2.1.4
  2. 秒杀商品超卖事故:Redis分布式锁请慎用!
  3. 微生物组-扩增子16S分析第12期(报名直播课免费参加线下2021.7)
  4. linux yum 安装mysql_Linux下使用yum安装MySQL
  5. Spring Boot使用mongo的GridFS模块
  6. java解压gz文件
  7. 使用mysqlbinlog恢复指定表
  8. 牛客网 【每日一题】6月11日题目精讲 背包
  9. post提交,WPF,Silverlight(加深记忆写一遍)
  10. 对VC++一些常见问题的整理
  11. 拓端tecdat|R语言法国足球联赛球员多重对应分析(MCA)
  12. 把想法变成现实-兄弟连IT教育
  13. Vue Canvas 实现电子签名 手写板
  14. 程序员修炼之道——通向务实的最高境界(第二版)
  15. 前端数据可视化之使用 canvas、svg、zrender画图
  16. 【Mac】微信视频对方听不见你的声音
  17. 【QGIS入门实战精品教程】10.1:QGIS基于DEM数据的地形分析案例教程
  18. 淘宝关键字搜索商品-v1
  19. Tetris项目总结
  20. 16位调色板和32位调色板_设计系统的调色板第一部分

热门文章

  1. 诺亚面向语音语义的深度学习研究进展
  2. Android初学者之轻松实现语音识别
  3. 从ADAS到无人驾驶 关键技术有哪些
  4. Vue入门八、非父子组件间通讯
  5. 从windows上传文件到linux,中文名乱码解决方法
  6. Jersey Restful Application with tomcat
  7. bootstrap select 插件两级联动
  8. emmet快速缩写展开的基本写法与心得
  9. 【干货】不同场景下 如何进行MySQL迁移
  10. 探究chrome下的开发工具的各功能