iOS进阶1--UIWebView缓存
来源:互联网 发布:桂林绿源网络 编辑:程序博客网 时间:2024/05/29 07:56
大家有没有遇到过项目有要求对UIWebView的请求数据进行缓存,在有缓存的情况下,从本地加载数据,如果没有缓存,或者缓存已经过期的情况下,则从服务端进行加载数据,并对其返还结果进行缓存操作,如果遇到这种需求,大家会有怎样的解决方案呢?以下是参考http://www.jianshu.com/p/7f3be7c30c77的解决方案。
第一种方案:
原理就是大多数的网络请求都会先调用这个类中的- (NSCachedURLResponse )cachedResponseForRequest:(NSURLRequest )request 这个方法,那我们只要重写这个类,就能达到本地缓存的目的了。
下面是大致的逻辑
1.判断请求中的request 是不是使用get方法,据资料显示一些本地请求的协议也会进到这个方法里面来,所以在第一部,要把不相关的请求排除掉。
2.判断缓存文件夹里面是否存在该文件,如果存在,继续判断文件是否过期,如果过期,则删除。如果文件没有过期,则提取文件,然后组成NSCacheURLResponse返回到方法当中。
3.在有网络的情况下,如果文件夹中不存在该文件,则利用NSConnection这个类发网络请求,再把返回的data和response 数据本地化存储起来,然后组成NSCacheURLResponse返回到方法当中。
具体代码如下:
1.定义一个CustomURLCache 继承于NSURLCache
@interface CustomURLCache : NSURLCache@property(nonatomic, assign) NSInteger cacheTime;@property(nonatomic, retain) NSString *diskPath;@property(nonatomic, retain) NSMutableDictionary *responseDictionary;- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path cacheTime:(NSInteger)cacheTime;@end
.m文件如下:
#import "CustomURLCache.h"#import "Reachability.h"@interface CustomURLCache(private)- (NSString *)cacheFolder;- (NSString *)cacheFilePath:(NSString *)file;- (NSString *)cacheRequestFileName:(NSString *)requestUrl;- (NSString *)cacheRequestOtherInfoFileName:(NSString *)requestUrl;- (NSCachedURLResponse *)dataFromRequest:(NSURLRequest *)request;- (void)deleteCacheFolder;@end@implementation CustomURLCache@synthesize cacheTime = _cacheTime;@synthesize diskPath = _diskPath;@synthesize responseDictionary = _responseDictionary;/**初始化方法 @param memoryCapacity 缓存内存大小,默认4M,4* 1024 * 1024 @param diskCapacity 硬盘大小,默认20M,20 * 1024 * 1024 @param path 缓存路径,默认(NSHomeDirectory)/Library/Caches/(current application name, [[NSProcessInfo processInfo] processName]) @param cacheTime 缓存有效时间 @return 自定义NSURLCache对象 */- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path cacheTime:(NSInteger)cacheTime { if (self = [self initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path]) { self.cacheTime = cacheTime; if (path) self.diskPath = path; else self.diskPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; self.responseDictionary = [NSMutableDictionary dictionaryWithCapacity:0]; } return self;}- (void)dealloc { [_diskPath release]; [_responseDictionary release]; [super dealloc];}//所有网络请求都会优先调用该方法,所有我们只要在这里重载这个方法,对请求进行处理即可- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request { if ([request.HTTPMethod compare:@"GET"] != NSOrderedSame) { return [super cachedResponseForRequest:request]; } //关键方法 return [self dataFromRequest:request];}- (void)removeAllCachedResponses { [super removeAllCachedResponses]; [self deleteCacheFolder];}- (void)removeCachedResponseForRequest:(NSURLRequest *)request { [super removeCachedResponseForRequest: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]; NSFileManager *fileManager = [NSFileManager defaultManager]; [fileManager removeItemAtPath:filePath error:nil]; [fileManager removeItemAtPath:otherInfoPath error:nil];}#pragma mark - custom url cache- (NSString *)cacheFolder { return @"URLCACHE";}- (void)deleteCacheFolder { NSString *path = [NSString stringWithFormat:@"%@/%@", self.diskPath, [self cacheFolder]]; NSFileManager *fileManager = [NSFileManager defaultManager]; [fileManager removeItemAtPath:path error:nil];}- (NSString *)cacheFilePath:(NSString *)file { NSString *path = [NSString stringWithFormat:@"%@/%@", self.diskPath, [self cacheFolder]]; NSFileManager *fileManager = [NSFileManager defaultManager]; BOOL isDir; if ([fileManager fileExistsAtPath:path isDirectory:&isDir] && isDir) { } else { [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; } return [NSString stringWithFormat:@"%@/%@", path, file];}- (NSString *)cacheRequestFileName:(NSString *)requestUrl { return [Util md5Hash:requestUrl];}- (NSString *)cacheRequestOtherInfoFileName:(NSString *)requestUrl { return [Util md5Hash:[NSString stringWithFormat:@"%@-otherInfo", requestUrl]];}/*关键方法,如果没有缓存,则返回nil,有则返回一个NSCachedURLResponse对象*/- (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) { //cacheTime == 0,则表示永久有效 NSInteger createTime = [[otherInfo objectForKey:@"time"] intValue]; if (createTime + self.cacheTime < [date timeIntervalSince1970]) { expire = true; } } if (expire == false) { NSLog(@"data from cache ..."); //从缓存读取数据,初始化一个NSCachedURLResponse对象 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; } //sendSynchronousRequest请求也要经过NSURLCache,从新进行数据缓存 __block NSCachedURLResponse * cachedResponse = nil; id boolExsite = [self.responseDictionary objectForKey:url]; if (boolExsite == nil) { [self.responseDictionary setValue:[NSNumber numberWithBool:TRUE] forKey:url]; // NSURLResponse *response = nil;// NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { if (response && data) { [self.responseDictionary removeObjectForKey:url]; } if (connectionError) { NSLog(@"error : %@", connectionError); NSLog(@"not cached: %@", request.URL.absoluteString); cachedResponse = nil; } NSLog(@"get request ... "); //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; } return nil;}@end
具体使用如下:
//关键:类初始化时进行,改变默认的NSURLCache- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { CustomURLCache *urlCache = [[CustomURLCache alloc] initWithMemoryCapacity:20 * 1024 * 1024 diskCapacity:200 * 1024 * 1024 diskPath:nil cacheTime:0]; //setSharedURLCache该方法可以使缓存类变为我们自定义的缓存方案 [CustomURLCache setSharedURLCache:urlCache]; [urlCache release]; } return self;}- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.frame]; webView.delegate = self; self.webView = webView; [webView release]; [self.view addSubview:_webView]; [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com/"]]];}- (void)didReceiveMemoryWarning{ [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. CustomURLCache *urlCache = (CustomURLCache *)[NSURLCache sharedURLCache]; [urlCache removeAllCachedResponses];}- (void)dealloc { [_webView release]; [super dealloc];}#pragma mark - webview- (void)webViewDidFinishLoad:(UIWebView *)webView { [MBProgressHUD hideHUDForView:self.view animated:YES];}- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { [MBProgressHUD hideHUDForView:self.view animated:YES];}- (void)webViewDidStartLoad:(UIWebView *)webView { MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; hud.mode = MBProgressHUDModeIndeterminate; hud.labelText = @"Loading...";}
注意: 这方案会返回多次 每一次链接相同的url(有网络的情况下,部分网页如:(百度),它这个url里面可能内嵌了很多其他的url,那其他的url可能每次都不一样,所以返回的request.url.absluteString 都不一样,这样导致每次系统会根据absoluteStr 来创建文件,则会越来越多;这种情况下是不适用的。
源码地址:https://github.com/lzhlewis2015/UIWebViewLocalCache
第二种方案:
+ (instancetype)requestWithURL:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval;//通过上面方法进行设置NSURLRequestCachePolicy- (void)loadWebView{ //可以每次请求的时候先去缓存里面读取,如果缓存里面没有的话再去网上加载 request = [NSURLRequest requestWithURL:urlcachePolicy:NSURLRequestReturnCacheDataElseLad timeoutInterval:10.]; NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; if (cachedResponse) { //cache已经存在 直接用web加载本地的数据 NSLog(@"cache存在 直接加载本地的数据"); [_WKWebView loadHTMLString:[[NSString alloc]initWithData:cachedResponse.data encoding:NSUTF8StringEncoding] baseURL:_request.URL];}}else { //cache还不存在 NSLog(@"cache不存在 需要从网络加载"); NSURLSessionDownloadTask *task = [[NSURLSession sharedSession]downloadTaskWithRequest:_request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSData *data = [NSData dataWithContentsOfURL:location]; NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:_request]; if ((!cachedResponse) && response && data) { NSCachedURLResponse *cachedURLResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data]; [[NSURLCache sharedURLCache]storeCachedResponse:cachedURLResponse forRequest:_request];} }]; [task resume]; [_WKWebView loadRequest:request];}}//这个清除缓存也很简单 [[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
- iOS进阶1--UIWebView缓存
- IOS UIWebView 离线缓存
- iOS开发UIWebView缓存
- IOS 清除UIWebView的缓存
- iOS WKWebView——UIWebView的进阶
- [ios] UIWebView的离线缓存【转】
- IOS 清除UIWebview的缓存以及cookie
- IOS 清除UIWebview的缓存以及cookie
- iOS控件—UIWebView缓存问题
- iOS--UIWebView清除缓存和Cookie
- iOS UI篇 - UIWebView缓存清除
- iOS清除UIWebView的缓存以及cookie
- ios 如何实现UIWebView的缓存
- iOS-UIWebview缓存并保证实时性
- UIWebView(进阶)
- ios开发进阶之网络06 网络安全 UIWebView
- [iOS进阶]iOS缓存机制详解
- 关于iOS开发UIWebView缓存相关问题的解决
- Bootstrap学习-图片
- PAT甲级1061. Dating (20)
- JS立即执行函数
- 团体程序设计天梯赛L2-009 抢红包
- 第七届蓝桥杯 省赛 JavaB组 凑算式
- iOS进阶1--UIWebView缓存
- STL源码剖析之traits编程技巧
- POJ 3279 Fliptile (反转)
- oracle--sql--倒叙和正序同时存在情况归纳
- 第二章 线性表
- 九度OJ 题目1054:字符串内排序
- 修改vim主题配色
- Android Sqlite库基本操作
- U3D插件 Build Report Tool 自述文件