iOS缓存机制及实战验证

来源:互联网 发布:java开平方函数 编辑:程序博客网 时间:2024/06/03 21:24

iOS缓存机制及实战验证

在开发中,我们需要考虑很多问题,不仅仅要考虑到用户的数据安全以及用户体验问题,还需要考虑我们平常深恶痛疾的流量问题。我不止一次的恶心那些相当耗费流量的软件,尤其是现在网页浏览的时候,我们的智能手机浏览速度快,而且加载的图片都是高清的,就导致流量哗哗的跑,上个月有两次,流量一分钟跑了300多兆,真的是。。。。哎,扯远了,所以,在很多时候,不管是基于用户没有网络浏览数据的出发点也好,基于节省用户流量的出发点也好,我们都需要对数据做本地缓存,我查阅了网上很多人写的帖子,都对缓存有介绍,在感谢他们乐意分享的同时,我还是有一些问题没有搞得很明白,所以还是自己研究下写出来比较好。

首先,我简单说一下iOS的缓存机制,iOS的缓存分为内存缓存(memory cache)和磁盘缓存(disk cache),我之前一直搞不清楚的就是这些东西是存放在哪里的,有的帖子说内存是放在沙盒的,但是后面又说程序退出后就没有了,那我就奇怪了,如果是放在沙盒的话,既然帖子里说程序退出之后就不存在了,那么肯定是放在tmp文件夹下的,但是就算是放在tmp文件夹下,那也是在机器重启之后才清楚的,这个地方绕了我半天,最终经过我的检测,确定了这两种缓存的存放位置:
内存缓存: 具体存放路径未知,推测是放在栈中或者堆中,因为程序重启之后,内存会被清空。(后面程序中我会实验)
磁盘缓存:存放在沙盒路径中的Library/Caches/作者名.工程名/ 文件夹下,(例如我的就是在Library/Caches/ZGL.TestPost 文件夹下),在该文件夹下有.db文件,就是我们的缓存文件。
平时我们操作的,都是磁盘缓存,内存缓存是不可以直接操作的。

下面就姨一个栗子来具体说明一下如何创建和使用缓存。(该工程以NSURLConnection发起网路请求,虽然该API在iOS 9.0后弃用,但是我们今天是只验证缓存,相比于NSURLSession,NSURLConnection的代理关联更少一些)。首先我们创建一个基本的网络请求:

NSURL *url = [NSURL URLWithString:@"http://m.mydrivers.com/app/newstoppic.aspx?id=141077031173.913300"];  //使用一个新闻的接口作为栗子    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:10];  //创建一个requestNSHTTPURLResponse *response; //创建httpResponse变量,发起NSURLConnection的时候需要使用    NSError *error;   //创建错误记录变量,用处同上NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];  //发起网络请求。接受数据,我这里发起的是同步请求NSLog(@"data==%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);//打印网络请求数据if (error != nil) {            NSLog(@"%@",[error localizedDescription]);//打印错误信息        }if (response]) {            NSLog(@"http.responseCode = %lu",response.statusCode);  NSLog(@"httpHeader=%@",response.allHeaderFields);//打印http头文件        }

运行结果如下:

2016-09-12 18:42:16.072 TestPost[2399:304073] data==[{"id":498794,"content":"","postdate":"2016/9/9 12:36:49","editor":"小路","desc":"","reviewcount":93,"ispass":"True","isdel":"False","title":"快播涉黄案尘埃落定:CEO王欣当庭认罪","icon":"http://news.mydrivers.com/img/topimg/20160909/190508296.jpg"},{"id":498790,"content":"","postdate":"2016/9/9 12:10:53","editor":"朝晖","desc":"","reviewcount":21,"ispass":"True","isdel":"False","title":"装X必备!6s改iPhone 7高亮黑保护套:好逼真","icon":"http://news.mydrivers.com/img/topimg/20160909/190511977.jpg"},{"id":498597,"content":"","postdate":"2016/9/8 9:21:05","editor":"雪花","desc":"","reviewcount":45,"ispass":"True","isdel":"False","title":"iPhone 7、7 Plus全球售价一览!国行大亮","icon":"http://news.mydrivers.com/img/topimg/20160908/191434246.jpg"}]2016-09-12 18:42:16.073 TestPost[2399:304073] http.responseCode = 2002016-09-12 18:42:16.073 TestPost[2399:304073] httpHeader={    "Cache-Control" = "public, max-age=600";    "Content-Length" = 802;    "Content-Type" = "text/html; charset=utf-8";    Date = "Mon, 12 Sep 2016 10:42:16 GMT";    Expires = "Mon, 12 Sep 2016 10:52:17 GMT";    "Last-Modified" = "Mon, 12 Sep 2016 10:42:17 GMT";    Server = "Microsoft-IIS/7.5";    Vary = "*";    "X-AspNet-Version" = "4.0.30319";    "X-Powered-By" = "ASP.NET";}

上面我们是一个基本的网络请求的发起及接收流程,貌似并没有提到关于缓存的东西,但是看这里,我们发起NSURLConnection的时候,设置了缓存策略,如下:

NSURLRequest    *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:10];  //创建一个request

其中cachePolicy:NSURLRequestReturnCacheDataElseLoad,这里我们设置了缓存策略,该参数是一个枚举值,在官方文档中有如下枚举可以选择:

typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy){    NSURLRequestUseProtocolCachePolicy = 0, 使用默认的缓存策略,在http协议里设定好的    NSURLRequestReloadIgnoringLocalCacheData = 1,忽略本地缓存,直接向网络请求数据    NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented  apple未实现该策略,不管他    NSURLRequestReloadIgnoringCacheData =   NSURLRequestReloadIgnoringLocalCacheData,  忽略本地缓存,直接向网络请求数据    NSURLRequestReturnCacheDataElseLoad = 2, 返回本地缓存的数据,否则从网络加载    NSURLRequestReturnCacheDataDontLoad = 3, 返回本地缓存数据,就算没有,也不去网络请求    NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented  未实现,不管他};

顺便说一下后面response.statusCode是该次请求状态码,200为正常;response.allHeaderFields是该次请求的请求头参数,数据长度,返回数据格式等。

说了这么多,我们该怎么去使用缓存呢,有下面两种方式:
一.手动获取本地缓存数据,示例如下:

NSURLCache *cache = [NSURLCache sharedURLCache]; //本地缓存是一个单利,获取全局的缓存单利文件NSCachedURLResponse *cacheResponse;cacheResponse = [cache cachedResponseForRequest:request]; //获取针对某一次请求的缓存NSLog(@"%@",[[NSString alloc]initWithData:cacheResponse.data encoding:NSUTF8StringEncoding]); //打印缓存数据

需要注意的是,我们可以自己设定内存缓存和磁盘缓存的大小,

[cache setMemoryCapacity:1*1024*1024]; //设置内存缓存[cache setDiskCapacity:5*1024*1024]; //设置磁盘缓存

如果我们不设置的话,默认的内存缓存大小是512000B,磁盘内存空间为10000000。如果磁盘缓存过多的话,我们可以调用下面的方法来清理数据:

- (void)removeCachedResponseForRequest:(NSURLRequest *)request;  清除某一次请求的缓存数据- (void)removeAllCachedResponses;清除全部的缓存数据- (void)removeCachedResponsesSinceDate:(NSDate *)date NS_AVAILABLE(10_10, 8_0); 清除从某一个时间点开始的缓存数据

我们可以通过查询当前的内存和缓存使用情况来判断当前内存使用率:

NSLog(@"打印缓存信息  \n内存空间:%lu  已使用空间:%lu \n磁盘空间:%lu  已使用空间%lu",[cache memoryCapacity],[cache currentMemoryUsage],[cache diskCapacity],[cache currentDiskUsage]);

输出如下:

2016-09-12 19:07:36.729 TestPost[2626:328876] 打印缓存信息  内存空间:512000  已使用空间:0 磁盘空间:10000000  已使用空间86016

当我们从网络请求一次数据的时候,该次数据会被保存在内存和缓存中,如果我们直接从缓存读取数据的话,那么则会将该数据在内存中保存一份,各位可以自己试一下。

二、自己建立在本地建立数据表来保存和管理数据,比如封装好的FMDB或者自己写Sqlite代码也可以。

一点小小的分享,完毕!

0 0