今天在看HTTP协议,看到了response头中的cache-control,因而就深刻的研究了一下。发现了iOS中一个一直被我忽略的类——NSURLCache类。php
NSURLCachehtml
NSURLCache用于缓存网络请求,也就是NSURLRequest,而后根据咱们设置的NSURLCache策略进行相应的缓存。web
首先介绍一下各类策略sql
策略 | 意义 |
UseProtocolCachePolicy数据库 |
默认行为 |
ReloadIgnoringLocalCacheData | 不使用缓存 |
ReloadIgnoringLocalAndRemoteCacheData* | 我是认真地,不使用任何缓存 |
ReturnCacheDataElseLoad | 使用缓存(无论它是否过时),若是缓存中没有,那从网络加载吧 |
ReturnCacheDataDontLoad | 离线模式:使用缓存(无论它是否过时),可是不从网络加载 |
ReloadRevalidatingCacheData* | 在使用前去服务器验证 |
其中ReloadIgnoringLocalAndRemoteCacheData和ReloadRevalidatingCacheData两种是没有实现的,能够不看。缓存
在建立对request使用cache的时候会让咱们选择以上的某种策略进行,也就是服务器
+ (instancetype)requestWithURL:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval;
该方法让咱们设置策略和时间,而后request会根据策略和时间来进行相应的调度。网络
感觉NSURLCache工具
这里使用默认的缓存策略ReturnCacheDataElseLoad缓存策略,spa
首先须要建立NSURLCache类
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:0 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:3]; connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; [connection start];
实现NSURLConnectionDelegate协议
-(void)connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"finish"); }
而后运行开一下请求,这里用的工具是Charles
能够看到只有一次请求,再看控制台输出
2015-08-04 09:29:55.297 requestCache[19405:6375355] finish 2015-08-04 09:29:55.301 requestCache[19405:6375355] finish 2015-08-04 09:29:55.310 requestCache[19405:6375355] finish 2015-08-04 09:29:55.451 requestCache[19405:6375355] finish 2015-08-04 09:29:55.618 requestCache[19405:6375355] finish 2015-08-04 09:29:55.784 requestCache[19405:6375355] finish 2015-08-04 09:29:55.984 requestCache[19405:6375355] finish 2015-08-04 09:29:56.120 requestCache[19405:6375355] finish
因此说屡次的请求只会进行一次请求,由于在内存中NSURLCache为咱们缓存了一份response,一旦有一样请求就会使用缓存。
缓存持久化
缓存若是设定本地磁盘就会为咱们自动进行持久化,修改NSURLCache建立代码
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 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:3]; NSURLCache * cache = [NSURLCache sharedURLCache]; NSData *contentData = [@"123" dataUsingEncoding:NSUTF8StringEncoding]; NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://172.16.25.44/test1.php"] MIMEType:@"text/html" expectedContentLength:1000 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); }
输出结果以下
2015-08-04 09:48:58.825 requestCache[19503:6441561] 123 2015-08-04 09:48:58.826 requestCache[19503:6441561] finish 2015-08-04 09:48:58.983 requestCache[19503:6441561] 123 2015-08-04 09:48:58.984 requestCache[19503:6441561] finish 2015-08-04 09:48:59.167 requestCache[19503:6441561] 123 2015-08-04 09:48:59.167 requestCache[19503:6441561] finish 2015-08-04 09:48:59.334 requestCache[19503:6441561] 123 2015-08-04 09:48:59.335 requestCache[19503:6441561] 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的,因此咱们想要添加内容就要建立一个可变副本增减内容。