原文出处: Yasin的简书

理论

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

缓存介绍

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

图片缓存思路

图片缓存流程图.png

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 进行内存缓存映射,并进行管理,当内存警告时就清空NSMutableDictionary。如果内存占用超过限制,则按照时间顺序进行删除。

硬盘缓存

就是我们常说的把数据保存在本地,比如FMDB,CoreData,归档,NSUserDefaults,NSFileManager等等,这里就不多说了。
图片缓存建议使用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 completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //使用’获取数据(NSURLSessionDataTask)‘的方式发起请求
  7. UIImage *image = [UIImage imageWithData:data];
  8. dispatch_async(dispatch_get_main_queue(), ^{
  9. weakSelf.imageView.image = image;
  10. });
  11. }];
  12. [task resume];

使用AFNetWorking下载图片

导入头文件#import "UIImageView+AFNetworking.h"
使用:[imageView setImageWithURL:url];
UIImageView+AFNetworking做了内存缓存,和基于NSURLSession的网络请求缓存

代码分析:

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

  1. UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
  2. //从内存缓存中读取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. }

【转载】基于AFNetWorking3.0的图片缓存分析的更多相关文章

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

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

  2. 基于AFNetworking3.0网络封装

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

  3. iOS_SN_基于AFNetworking3.0网络封装

    转发文章,原地址:http://www.henishuo.com/base-on-afnetworking3-0-wrapper/?utm_source=tuicool&utm_medium= ...

  4. 基于AFNetworking3.0的网络封装

    1.创建名为HTTPMethod(自己随便起名字)的头文件 2.导入AFNetworking头文件(在github上下载最新版): #import "AFNetworking.h" ...

  5. Android开发笔记——图片缓存、手势及OOM分析

    把图片缓存.手势及OOM三个主题放在一起,是因为在Android应用开发过程中,这三个问题经常是联系在一起的.首先,预览大图需要支持手势缩放,旋转,平移等操作:其次,图片在本地需要进行缓存,避免频繁访 ...

  6. (转)基于FFPMEG2.0版本的ffplay代码分析

    ref:http://zzhhui.blog.sohu.com/304810230.html 背景说明 FFmpeg是一个开源,免费,跨平台的视频和音频流方案,它提供了一套完整的录制.转换以及流化音视 ...

  7. MUI - 基于plus.downloader的图片懒加载功能,支持本地缓存

    基于plus.downloader的图片懒加载功能,支持本地缓存 简单说一下 在app中,对一些变动不频繁的图片数据(如个人头像等),是需要存储在本地的.我相信这对大多数的app都是强需求的. 怎么使 ...

  8. 前端图片缓存之通过img标签加载GIF只能播放一次问题(转载)

    最近项目中要求再网页中插入一张gif图片,让用户每次到达该位置时动一次,所以我们就制作了一张只动一次的gif图片通过img标签引入.当用户进入该位置时,通过remove()清除图片然后重新append ...

  9. Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解

    转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/26810303),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...

随机推荐

  1. linux less-分屏上下翻页浏览文件内容

    博主推荐:获取更多 linux文件内容查看命令 收藏:linux命令大全 less命令的作用与more十分相似,都可以用来浏览文字档案的内容,不同的是less命令允许用户向前或向后浏览文件,而more ...

  2. 通过request对象获取客户端的相关信息

    通过request对象获取客户端的相关信息 制作人:全心全意 通过request对象可以获取客户端的相关信息.例如HTTP报头信息.客户信息提交方式.客户端主机IP地址.端口号等等. request获 ...

  3. 使用js将Unix时间戳转换为普通时间

    var unixtime=1358932051;formatTime (time) { let unixtime = time let unixTimestamp = new Date(unixtim ...

  4. 将网络图片转换为base64

    public static function htmlPdf() { $img_path = Env::get('ROOT_PATH').'/public/images/wechat/user.jpg ...

  5. RequestMapping注解_修饰类

    [使用RequestMapping映射请求] 1.Spring MVC使用 @RequestMapping 注解为控制器指定可以处理哪些URL请求. 2.在控制器的类定义及方法定义处都可以标注. @R ...

  6. 在eclipse中如何在大量项目中查找指定文件

    在eclipse中如果希望在大量的项目中寻找指定的文件可不是一件轻松的事,还好eclipse提供了强大的搜索功能. 我们可以通过通配符或正则表达式来设定查寻条件,下面是操作示例: ctrl+h 打开搜 ...

  7. POJ 3630

    Phone List Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 20894 Accepted: 6532 Descripti ...

  8. 转载 - Python里面关于 模块 和 包 和 __init__.py 的一些事

    出处:http://www.cnblogs.com/tqsummer/archive/2011/01/24/1943273.html python中的Module是比较重要的概念.常见的情况是,事先写 ...

  9. Inversion

    Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 4176   Accepted: 1857 Description The i ...

  10. 线程调度策略SCHED_RR(轮转法)和SCHED_FIFO(先进先出)之对照

    我们在用pthread创建线程时,能够指定调度策略policy--SCHED_OTHER(默认).SCHED_RR和SCHED_FIFO.这里TALK一下两个实时策略--SCHED_RR和SCHED_ ...