NSURLCache使用和UIWebView URL 拦截
现在因为项目需要更新版本,采用缓存的策略要发生改变。之前的版本在展示新闻后台返回的html内容所以之前的缓存策略只需要将html内容写入到文件中即可。现在新版本新闻详情的内容变得更加的复杂多样,所以现在直接的采用网页展示,也就是后台只会返回一个链接,至于UIwebView的缓存就需要自己去重新的定义了。
查了很多的博客和文档,发现webView本身是由缓存的,也就是NSURLCache,但是NSURLCache不满足需求,所以只能自己去定义。官方对NSURLCache虽然说是内存缓存和磁盘缓存相结合的,实际上只有内存缓存而且只有4M,另外就是现在混存的趋势时,定时清理,所以必须自己去复写NSURLCache来实现更多的需求。
(-)方法介绍
首先,看看NSURLCache的一些方法介绍:
初始化相关的几个方法:sharedURLCache;setSharedURLCache;initWithMemoryCapacity
(1) sharedURLCache方法返回一个NSURLCache实例。
默认情况下,内存是4M,4* 1024 * 1024;Disk为20M,20 * 1024 * 1024;路径在(NSHomeDirectory)/Library/Caches/(current application name, [[NSProcessInfo processInfo] processName])
(2)setSharedURLCache 可以通过这个方法来改变默认的NSURLCache。
(3)通过initWithMemoryCapacity 来定制自己的NSURLCache
cache使用相关的几个方法:
cachedResponseForRequest;//缓存请求
storeCachedResponse;//存储缓存
removeCachedResponseForRequest;//删除缓存请求
removeAllCachedResponses;//删除所以缓存请求
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
//如果对应的NSURLRequest没有cached的response那么返回nil
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request;
//为特定的NSURLRequest做cache
- (void)removeCachedResponseForRequest:(NSURLRequest *)request;
//移除特定NSURLRequest的cache
- (void)removeAllCachedResponses;
//移除所有的cache
(二)自定义cache
我们这边的需求将所有的数据写入到文件中,过期后将数据清除掉。所以我这里只需要重写
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)reques
这个方法即可
。
下面是核心代码:
#pragma mark - super
-(NSCachedURLResponse
*)cachedResponseForRequest:(NSURLRequest*)request{
if ([request.HTTPMethod compare:@"GET"] != NSOrderedSame) {
return [super cachedResponseForRequest:request];
}
return [self customResponseForRequest:request];
}
#pragma mark - private
-(NSString *)getFileName:(NSString *)url{
return [url getMd5_32Bit];
}
-(NSString *)getOtherInfoName:(NSString *)url{
return [[NSString stringWithFormat:@"%@-otherInfo",url] getMd5_32Bit];
}
- (NSString *)cacheFilePath:(NSString *)fileName{
NSString *filePath = [NSStringstringWithFormat:@"URLCache/%@",fileName];
NSString*path = kFilePathAtCachWithName(filePath);
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDir;
if([fileManager fileExistsAtPath:path isDirectory:&isDir] && isDir) {
} else{
[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
}
return path;
}
-(NSCachedURLResponse*)customResponseForRequest:(NSURLRequest*)request{
NSString *url = request.URL.absoluteString;//请求的链接
NSString*fileName = [self getFileName:url];//缓存的文件名
NSString*otherInfoName = [self getOtherInfoName:url];//缓存信息的文件名
NSString*filePath = [self cacheFilePath:fileName];//缓存的目录路径
NSString*otherInfoPath = [self cacheFilePath:otherInfoName];//缓存信息字典路径
NSFileManager *fileManger = [NSFileManager defaultManager];
if ([fileManger fileExistsAtPath:filePath]) {
//当文件名存在的时候
NSDate*date = [NSDate date];
BOOL isOverdue = YES;
NSDictionary *dicInfo = [NSDictionarydictionaryWithContentsOfFile:otherInfoPath];
if(self.catchTime > 0 && dicInfo) {
NSDate*createDate = dicInfo[kTimeKey];
double createTime = [date timeIntervalSinceDate:createDate];
if (createTime < self.catchTime) {
isOverdue = NO;
}
}
if (!isOverdue) {
//
没有过期
// NSLog(@"访问缓存数据
..");
NSData *data = [NSDatadataWithContentsOfFile:filePath];
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:dicInfo[kMIMETypeKey] expectedContentLength:data.lengthtextEncodingName:dicInfo[kTextEncodingNameKey]];
NSCachedURLResponse *cacheResponse = [[NSCachedURLResponsealloc] initWithResponse:response data:data];
return cacheResponse;
}else{
//已经过期删除信息
[fileManger removeItemAtPath :filePath error:nil];
[fileManger removeItemAtPath :otherInfoPath error:nil];
}
}
BOOL isExsit = [[self.dicResponse objectForKey:url] boolValue];
if (!isExsit) {
[self .dicResponse setObject:@(YES) forKey:url];
// NSLog(@"网络请求数据...");
__block NSCachedURLResponse *cacheResponse = nil;
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse*response, NSData *data, NSError *connectionError) {
//移除请求记录
[self .dicResponse removeObjectForKey:url];
if (data && response) {
NSMutableDictionary *dicInfo = [NSMutableDictionarydictionary];
[dicInfo setObject :[NSDate date] forKey:kTimeKey];
[dicInfo setObject :kUnNilStr(response.MIMEType) forKey:kMIMETypeKey];
[dicInfo setObject :kUnNilStr(response.textEncodingName) forKey:kTextEncodingNameKey];
BOOL state = [data writeToFile:filePath atomically:NO];
NSLog(@"%d",state);
[dicInfo writeToFile :otherInfoPath atomically:YES];
cacheResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
}
}];
return cacheResponse;
}else{
// NSLog(@"该请求已存在
...");
}
return nil;
}
ps: 这操蛋的博客,居然不支持代码格式,看上去怪怪的。
另外还可针对不同的请求来缓存,因为现在还没有这个需求,所以现在就没有添加进去。有不足的地方希望能收到更多的宝贵意见。
ps:ios8下面遇到的操蛋问题就是把NSURlCache必须设置在程序启动时才能有效,另外就是要区分非web的请求,只要在请求头中设置个判断的标志即可。此处不知道查了多少英文文档才知道这么点
本文链接http://blog.sina.com.cn/s/blog_7da8833c0102w2q7.html 在开始看iOS UIWebView URL拦截,看到这里,顺便就整理下http://www.cocoachina.com/ios/20150626/12161.html?utm_source=tuicool&utm_medium=referral