iOS开发-NSURLCache(缓存)

来源:互联网 发布:psp游戏数据已损坏 编辑:程序博客网 时间:2024/06/06 01:45

今天在看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: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] finish2015-08-04 09:29:55.301 requestCache[19405:6375355] finish2015-08-04 09:29:55.310 requestCache[19405:6375355] finish2015-08-04 09:29:55.451 requestCache[19405:6375355] finish2015-08-04 09:29:55.618 requestCache[19405:6375355] finish2015-08-04 09:29:55.784 requestCache[19405:6375355] finish2015-08-04 09:29:55.984 requestCache[19405:6375355] finish2015-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] 1232015-08-04 09:48:58.826 requestCache[19503:6441561] finish2015-08-04 09:48:58.983 requestCache[19503:6441561] 1232015-08-04 09:48:58.984 requestCache[19503:6441561] finish2015-08-04 09:48:59.167 requestCache[19503:6441561] 1232015-08-04 09:48:59.167 requestCache[19503:6441561] finish2015-08-04 09:48:59.334 requestCache[19503:6441561] 1232015-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的,所以我们想要添加内容就要创建一个可变副本增减内容。


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 新手机开不了机怎么办 三星a9屏幕漏液怎么办 小米note后面玻璃碎了怎么办 换手机微信钱包怎么办 内外屏一体手机屏幕碎了怎么办 苹果手机显示屏坏了怎么办 华为手机屏裂了怎么办 乐视手机屏坏了怎么办 红米手机触屏失灵怎么办 小米4排线断了怎么办 红米3x屏幕难点怎么办 华为p7屏幕不亮怎么办 红米5外屏碎了怎么办 小米电视碎屏了怎么办 oppo手机第二屏幕打不开怎么办 红米note3屏幕裂了怎么办 小米3屏幕烂了怎么办 苹果x屏幕触屏不灵怎么办 票买好了身份证丢了怎么办 广发信用卡身份证到期了怎么办 人在外地身份证丢了怎么办 人在国外身份证丢了怎么办 身份证丢了户口本不在怎么办 在北京身份证过期了怎么办 没社保卡怎么办厦门健康卡 扬州市民卡丢了怎么办 扬州市民卡坏了怎么办 重庆社保卡坏了怎么办 社保卡丢了看病怎么办 社保卡丢了买药怎么办 常州社保卡丢了怎么办 深圳社保卡掉了怎么办 上海医保卡丢了怎么办 户口转到西安后医保怎么办 上海医保卡掉了怎么办 上海医保本丢了怎么办? 新版医保卡丢了怎么办 武汉社保卡掉了怎么办 职工社保卡丢了怎么办 杭州社保卡丢了怎么办 农村医疗卡丢了怎么办