今天在看HTTP协议,看到了response头中的cache-control,于是就深入的研究了一下。发现了iOS中一个一直被我忽略的类——NSURLCache类。

NSURLCache

NSURLCache用于缓存网络请求,也就是NSURLRequest,然后根据我们设置的NSURLCache策略进行相应的缓存。

首先介绍一下各种策略

策略 意义

UseProtocolCachePolicy

 默认行为
 ReloadIgnoringLocalCacheData  不使用缓存
 ReloadIgnoringLocalAndRemoteCacheData*  我是认真地,不使用任何缓存
 ReturnCacheDataElseLoad  使用缓存(不管它是否过期),如果缓存中没有,那从网络加载吧
 ReturnCacheDataDontLoad  离线模式:使用缓存(不管它是否过期),但是从网络加载
 ReloadRevalidatingCacheData* 在使用前去服务器验证 

其中ReloadIgnoringLocalAndRemoteCacheData和ReloadRevalidatingCacheData两种是没有实现的,可以不看。

在创建对request使用cache的时候会让我们选择以上的某种策略进行,也就是

+ (instancetype)requestWithURL:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval;

该方法让我们设置策略和时间,然后request会根据策略和时间来进行相应的调度。

感受NSURLCache

这里使用默认的缓存策略ReturnCacheDataElseLoad缓存策略,

首先需要创建NSURLCache类

NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity: *  *  diskCapacity: diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];

1.这里可以看到,创建参数我们制定了 4 * 1024 * 1024的内存(4MB) ,没有使用磁盘空间。

2.NSURLCache使用[NSURLCache sharedURLCache]创建默认的的缓存行为,默认为 4(MB) 内存和 20(MB)磁盘空间,这里我们使用自定义的,所以要setSharedCache。

然后创建request和connection进行请求

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://172.16.25.44/test1.php"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];

实现NSURLConnectionDelegate协议

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"finish");
}

然后运行开一下请求,这里用的工具是Charles

可以看到只有一次请求,再看控制台输出

-- ::55.297 requestCache[:] finish
-- ::55.301 requestCache[:] finish
-- ::55.310 requestCache[:] finish
-- ::55.451 requestCache[:] finish
-- ::55.618 requestCache[:] finish
-- ::55.784 requestCache[:] finish
-- ::55.984 requestCache[:] finish
-- ::56.120 requestCache[:] finish

所以说多次的请求只会进行一次请求,因为在内存中NSURLCache为我们缓存了一份response,一旦有同样请求就会使用缓存。

缓存持久化

缓存如果设定本地磁盘就会为我们自动进行持久化,修改NSURLCache创建代码

    NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity: *  *  diskCapacity: *  *  diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];

设置了20MB的本地磁盘,然后运行程序,进行请求发现还是请求一次没有变化。但是在次运行程序进行请求就会发现,一次远程请求也不会进行了!

打开沙盒,发现在 Library/Caches/bundleId+项目名/下面有三个文件

这不就是sqlite么!原来NSURLCache帮我们用sqlite将请求存入了数据库,然后当有相同请求时就会调用缓存!

可以想到webView如果加载一个静态页面不用只用请求一次,并且在效果要更新的时候远程请求会有多爽!

默认策略

默认策略是 UseProtocolCachePolicy 从字面上来看是说,使用协议缓存策略,但是什么是协议缓存策略呢?

在HTTP协议的response头中,有一个字段是cache-control,由服务器来告诉客户端如何使用缓存。

下面是一个response头

可以看到cache-control指定的行为是public,max-age=5

这里先介绍一下各种指令

对应上表,可以看出了刚才响应头是要求缓存所有内容,缓存5秒失效,5秒后还要请求远程服务器。

对应PHP就是header("Cache-Control:public,max-age=5");

伪造响应

如果我们想让一些请求,有特定的响应,我们可以自己来制作响应

    NSLog(@"%@",[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]);

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://172.16.25.44/test1.php"] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:];
NSURLCache * cache = [NSURLCache sharedURLCache]; NSData *contentData = [@"" dataUsingEncoding:NSUTF8StringEncoding]; NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://172.16.25.44/test1.php"] MIMEType:@"text/html" expectedContentLength: textEncodingName:@"UTF-8"];
NSCachedURLResponse *cacheRespone = [[NSCachedURLResponse alloc] initWithResponse:response data:contentData]; [cache storeCachedResponse:cacheRespone forRequest:request]; connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];

如上代码,创建了一个针对@"http://172.16.25.44/test1.php"请求的响应,并且让 cache 对该响应进行了存储。

实现

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",dataString);
}

输出结果如下

-- ::58.825 requestCache[:]
-- ::58.826 requestCache[:] finish
-- ::58.983 requestCache[:]
-- ::58.984 requestCache[:] finish
-- ::59.167 requestCache[:]
-- ::59.167 requestCache[:] finish
-- ::59.334 requestCache[:]
-- ::59.335 requestCache[:] finish

可以看到输出的是我们自定义的123,而不是服务器返回的1。

修改响应内容

修改响应内容需要我们实现NSURLConnectionDataDelegate 协议并实现

-(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
NSMutableData *mutableData = [[cachedResponse data] mutableCopy]; //添加数据 NSCachedURLResponse *response = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:mutableData];
return response;
}

应为 NSCachedURLResponse 的属性都是readonly的,所以我们想要添加内容就要创建一个可变副本增减内容。

iOS网络——NSURLCache设置网络请求缓存的更多相关文章

  1. linux网络基础设置 以及 软件安装

    ifconfig #查看所有已激活的网卡信息 临时配置 #yum install net-tools -y 默认ifconfig是没有安装的,可能需要安装 ifconfig eth0 #查看单独一块网 ...

  2. NSCache和NSURLCache、网络缓存优化

    本文目录 一种缓存优化方案 响应头'Last-Modified'和请求头'If-Modified-Since' 'Keep-Alive'响应头和不离线的URLSession 'Expires'响应头 ...

  3. iOS 自己封装的网络请求,json解析的类

    基本上所有的APP都会涉及网络这块,不管是用AFNetWorking还是自己写的http请求,整个网络框架的搭建很重要. 楼主封装的网络请求类,包括自己写的http请求和AFNetWorking的请求 ...

  4. NSURLCache、网络监測状态

    有时候.对同一个URL请求多次.返回的数据可能一样的: 比方server上的某张图片.不管下载多少次,返回的数据都是一样的.可是这些情况会造成下面问题: 1,用户流量的浪费. 2.程序响应速度不够快 ...

  5. iOS UI高级之网络编程(HTTP协议)

    HTTP协议的概念 HTTP协议,Hyper Text Transfer Protocol (超文本传输协议)是用于从万维网服务器传送超文本到本地浏览器的传输协议,HTTP是一个应用层协议,由请求和响 ...

  6. iOS开发之AFNetworking网络编程

    众所周知,苹果搞的一套框架NSContention发送请求与接收请求的方式十分繁琐.操作起来很不方便.不仅要做区分各种请求设置各种不同的参数,而且还要经常在多线程里操作,同时还要对请求与返回的数据做各 ...

  7. PHP-02.文件上传、php保存/转移上传的文件、常见的网络传输协议、请求报文及属性、响应报文及属性

    关系数组 array("key"=>"value",...) ; get没有数据大小的限制 post上传大小没有限制 不指定上传方式,默认是get 文件上 ...

  8. Android开发中网络代理设置实用总结

    一.背景 进行Android项目开发时,跟网络代理基本上天天都在打交道.通常情况下,至少有三个场景中经常用到网络代理: 1,经常通过Chrome访问Google等国外的技术网站,如通过SS工具等: 2 ...

  9. iOS下的实际网络连接状态检测(转)

    序言 网络连接状态检测对于我们的iOS app开发来说是一个非常通用的需求.为了更好的用户体验,我们会在无网络时展现本地或者缓存的内容,并对用户进行合适的提示.对绝大部分iOS开发者来说,从苹果示例代 ...

随机推荐

  1. php第十五节课

    租房表 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3. ...

  2. Node.js之错误处理

    Node.js之错误处理 1. 使用 domain 模块处理错误 try..catch 多用于捕捉同步方法中的抛出错误,但不能用try..catch捕捉异步方法中抛出de错误 如: 1 var htt ...

  3. Luogu P2068 统计和

    P2068 统计和 题目描述 给定一个长度为n(n<=100000),初始值都为0的序列,x(x<=10000)次的修改某些位置上的数字,每次加上一个数,然后提出y (y<=1000 ...

  4. 《ABCD组》第八次作业:ALPHA冲刺

    <ABCD组>第八次作业:ALPHA冲刺 项目 内容 这个作业属于哪个课程 http://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://ww ...

  5. 暑假集训D17总结

    考试 玄学的一次考试= = T1乱搞 只会乱搞出前二十分  然后真的拿了二十分 T2模拟 自己造数据 没有一个是在十分钟内跳出来的 然后竟然A了 T3暴力 觉得如果老爷机心情不好就会被卡到20  然后 ...

  6. [bzoj1925][Sdoi2010]地精部落_递推_动态规划

    地精部落 bzoj-1925 Sdoi-2010 题目大意:给你一个数n和模数p,求1~n的排列中满足每一个数的旁边两个数,要么一个是边界,要么都比它大,要么都比它小(波浪排列个数) 注释:$1\le ...

  7. 4.非关系型数据库(Nosql)之mongodb:普通索引,唯一索引

     一:普通索引 1创建一个新的数据库 > use toto; switched to db toto > show dbs; admin (empty) local 0.078GB & ...

  8. SAP 金税接口增强 BADI

      SAP与金税连接有两种方式:组件接口及文本接口. 文本接口为例: 1.SAP取发票数据.主要来自合同,销售订单,交货单.发票,客户供应商主数据等 2.SAP处理:合并.拆分,折扣等 3.导出TXT ...

  9. requireJS使用shim注入非标准模块详解

    在javascript中定义全局变量有2种方式,本质上是等价的,都是向window对象注入属性或者方法. // global.js var g_name = "aty"; wind ...

  10. Python游戏server开发日记(一)目标

    到了新的环境.老大让我有空研究下一代server技术,作为一个长期任务. 新的server想达到的目标: 1.分布式系统,对象(Entity)之间的关系类似于Actor模型. 2.逻辑服务,是单进程. ...