UIWebView---UIWebView实现离线浏览
来源:互联网 发布:程序员是吃青春饭吗 编辑:程序博客网 时间:2024/05/16 12:44
参考
http://re-reference.iteye.com/blog/1391408
http://nshipster.cn/nsurlcache/
http://blog.csdn.net/mad2man/article/details/30285001
SDK里绝大部分的网络请求都会访问[NSURLCache sharedURLCache]这个对象,它的cachedResponseForRequest:方法会返回一个NSCachedURLResponse对象。如果这个NSCachedURLResponse对象不为nil,且没有过期,那么就使用这个缓存的响应,否则就发起一个不访问缓存的请求。
要注意的是NSCachedURLResponse对象不能被提前释放,除非UIWebView去调用NSURLCache的removeCachedResponseForRequest:方法,原因貌似是UIWebView并不retain这个响应。而这个问题又很头疼,因为UIWebView有内存泄露的嫌疑,即使它被释放了,也很可能不去调用上述方法,于是内存就一直占用着了。
顺便说下NSURLRequest对象,它有个cachePolicy属性,只要其值为NSURLRequestReloadIgnoringLocalCacheData的话,就不会访问缓存。可喜的是这种情况貌似只有在缓存里没取到,或是强制刷新时才可能出现。
实际上NSURLCache本身就有磁盘缓存功能,然而在iOS上,NSCachedURLResponse却被限制为不能缓存到磁盘(NSURLCacheStorageAllowed被视为NSURLCacheStorageAllowedInMemoryOnly)。
不过既然知道了原理,那么只要自己实现一个NSURLCache的子类,然后改写cachedResponseForRequest:方法,让它从硬盘读取缓存即可。
第一种重写NSURLCache修改cachedResponseForRequest
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request { if ([request.HTTPMethod compare:@"GET"] != NSOrderedSame) { return [super cachedResponseForRequest:request]; } NSURL *url = request.URL; if (![supportSchemes containsObject:url.scheme]) { return [super cachedResponseForRequest:request]; } return [self dataFromRequest:request];}- (NSCachedURLResponse *)dataFromRequest:(NSURLRequest *)request { NSString *url = request.URL.absoluteString; NSString *fileName = [self cacheRequestFileName:url]; NSString *otherInfoFileName = [self cacheRequestOtherInfoFileName:url]; NSString *filePath = [self cacheFilePath:fileName]; NSString *otherInfoPath = [self cacheFilePath:otherInfoFileName]; NSDate *date = [NSDate date]; // 判断磁盘里面是否有本文件如果有就加载缓存 NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:filePath]) { BOOL expire = false; NSDictionary *otherInfo = [NSDictionary dictionaryWithContentsOfFile:otherInfoPath]; // 判断是否过期 if (self.cacheTime > 0) { NSInteger createTime = [[otherInfo objectForKey:@"time"] intValue]; if (createTime + self.cacheTime < [date timeIntervalSince1970]) { expire = true; } } if (expire == false) { NSLog(@"data from cache ..."); NSData *data = [NSData dataWithContentsOfFile:filePath]; NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:[otherInfo objectForKey:@"MIMEType"] expectedContentLength:data.length textEncodingName:[otherInfo objectForKey:@"textEncodingName"]]; NSCachedURLResponse *cachedResponse = [[[NSCachedURLResponse alloc] initWithResponse:response data:data] autorelease]; [response release]; return cachedResponse; } else { NSLog(@"cache expire ... "); [fileManager removeItemAtPath:filePath error:nil]; [fileManager removeItemAtPath:otherInfoPath error:nil]; } } if (![Reachability networkAvailable]) { return nil; } // 如果缓存已经过期 而且有网络的话 __block NSCachedURLResponse *cachedResponse = nil; //sendSynchronousRequest请求也要经过NSURLCache id boolExsite = [self.responseDictionary objectForKey:url]; if (boolExsite == nil) { [self.responseDictionary setValue:[NSNumber numberWithBool:TRUE] forKey:url]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data,NSError *error) { if (response && data) { [self.responseDictionary removeObjectForKey:url]; if (error) { NSLog(@"error : %@", error); NSLog(@"not cached: %@", request.URL.absoluteString); cachedResponse = nil; } NSLog(@"cache url --- %@ ",url); //save to cache NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%f", [date timeIntervalSince1970]], @"time", response.MIMEType, @"MIMEType", response.textEncodingName, @"textEncodingName", nil]; [dict writeToFile:otherInfoPath atomically:YES]; [data writeToFile:filePath atomically:YES]; cachedResponse = [[[NSCachedURLResponse alloc] initWithResponse:response data:data] autorelease]; } }]; return cachedResponse; //NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; } return nil;}
通过MD5hash生成文件名
MD5hash,哈希值计算器,是一款md5校验工具。每个文件都可以用Hash MD5验证程序算出一个固定的MD5码来。
- (NSString *)cacheRequestFileName:(NSString *)requestUrl { return [Util md5Hash:requestUrl];}- (NSString *)cacheRequestOtherInfoFileName:(NSString *)requestUrl { return [Util md5Hash:[NSString stringWithFormat:@"%@-otherInfo", requestUrl]];}
第二种利用ASIHTTPRequest来缓存
ASIHTTPRequest,ASIDownloadCache 和 ASIWebPageRequest
首先我得说,这确实是个很好的框架,使用起来确实很方便,但是对于缓存这个问题,好像也跟第二点提到的效果差不多,加载速度没有明显的提升,离线模式下也无法加载。这是实现的代码:
- -(void)loadURL:(NSURL*)url
- {
- ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
- //ASIWebPageRequest *request= [ASIWebPageRequest requestWithURL:url];
- [request setDelegate:self];
- //[request setUrlReplacementMode:ASIReplaceExternalResourcesWithData];
- [request setDidFailSelector:@selector(webPageFetchFailed:)];
- [request setDidFinishSelector:@selector(webPageFetchSucceeded:)];
- //设置缓存
- [request setDownloadCache:[ASIDownloadCache sharedCache]];
- //[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
- [request setCachePolicy:ASIAskServerIfModifiedWhenStaleCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy];
- [request setDownloadDestinationPath:[[ASIDownloadCache sharedCache]pathToStoreCachedResponseDataForRequest:request]];
- [request startAsynchronous];
- }
-
-
-
- - (void)webPageFetchFailed:(ASIHTTPRequest *)theRequest
- {
- // Obviously you should handle the error properly...
- NSLog(@"%@",[theRequest error]);
- NSString *path = [[NSBundle mainBundle] pathForResource:@"error1.html" ofType:nil inDirectory:@"WebResources/Error"];
- NSURL *url=[NSURL fileURLWithPath:path];
- [viewer loadRequest:[NSURLRequest requestWithURL:url]];
- }
-
- - (void)webPageFetchSucceeded:(ASIHTTPRequest *)theRequest
- {
- NSString *response = [NSString stringWithContentsOfFile:
- [theRequest downloadDestinationPath] encoding:[theRequest responseEncoding] error:nil];
- // Note we're setting the baseURL to the url of the page we downloaded. This is important!
- [viewer loadHTMLString:response baseURL:[theRequest url]];
- //[viewer loadHTMLString:response baseURL:nil];
- }
- -(void)loadURL:(NSURL*)url
- {
- ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
- //ASIWebPageRequest *request= [ASIWebPageRequest requestWithURL:url];
- [request setDelegate:self];
- //[request setUrlReplacementMode:ASIReplaceExternalResourcesWithData];
- [request setDidFailSelector:@selector(webPageFetchFailed:)];
- [request setDidFinishSelector:@selector(webPageFetchSucceeded:)];
- //设置缓存
- [request setDownloadCache:[ASIDownloadCache sharedCache]];
- //[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
- [request setCachePolicy:ASIAskServerIfModifiedWhenStaleCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy];
- [request setDownloadDestinationPath:[[ASIDownloadCache sharedCache]pathToStoreCachedResponseDataForRequest:request]];
- [request startAsynchronous];
- }
- - (void)webPageFetchFailed:(ASIHTTPRequest *)theRequest
- {
- // Obviously you should handle the error properly...
- NSLog(@"%@",[theRequest error]);
- NSString *path = [[NSBundle mainBundle] pathForResource:@"error1.html" ofType:nil inDirectory:@"WebResources/Error"];
- NSURL *url=[NSURL fileURLWithPath:path];
- [viewer loadRequest:[NSURLRequest requestWithURL:url]];
- }
- - (void)webPageFetchSucceeded:(ASIHTTPRequest *)theRequest
- {
- NSString *response = [NSString stringWithContentsOfFile:
- [theRequest downloadDestinationPath] encoding:[theRequest responseEncoding] error:nil];
- // Note we're setting the baseURL to the url of the page we downloaded. This is important!
- [viewer loadHTMLString:response baseURL:[theRequest url]];
- //[viewer loadHTMLString:response baseURL:nil];
- }
- UIWebView---UIWebView实现离线浏览
- UIWebView实现离线浏览
- UIWebView实现离线浏览
- UIWebView实现离线浏览
- UIWEBView实现离线浏览
- 为UIWebView实现离线浏览
- 为UIWebView实现离线浏览
- 为UIWebView实现离线浏览
- 为UIWebView实现离线浏览
- 为UIWebView实现离线浏览
- [转] 为UIWebView实现离线浏览
- UIWebview点击图片实现大图浏览
- 使用NSURLProtocol实现UIWebView的离线缓存
- 使用NSURLProtocol实现UIWebView的离线缓存
- 使用NSURLProtocol实现UIWebView的离线缓存
- UIwebView实现html的离线缓存
- 使用NSURLProtocol实现UIWebView的离线缓存
- 使用NSURLProtocol实现UIWebView的离线缓存
- Fanwe 方维多语商城建站系统接入手机短信功能--支持注册验证、订单通知等
- 读书笔记_Java程序性能优化_Chap1.概述
- 数据库建表技巧
- MESI-CPU缓存一致性协议
- Java 8新特性探究(五)重复注解(repeating annotations)
- UIWebView---UIWebView实现离线浏览
- 二维的完全背包
- 七牛qboxrsctl 部分使用的shell命令
- View 绘制流程
- WCF中配置文件解析
- 兼容sdk7&iOS7的issue解决小片段总结
- 路由汇聚与子网划分应用题
- 整型,字符型,字符串型双重快排
- 1.3、C++程序的构成及书写格式