方式一:截取请求正则、图片缓存

实现webview缓存网页内容难点在缓存图片上。html代码的缓存相对简单,
具体实现思路是这样的:
第1步、先获取html页面里所有图片地址。
方法一:离线获取获取到html代码。html代码你可以把他理解成是一个很长的字符串。通过正则表达式把这个html页面里的所有img标签url。如果是相对url,就加上host。如果是绝对url,就直接下载。这样这个页面里的所有图片路径都拿到了。
方法一的获取img标签url的正则表达式:
NSString *urlPattern = @"<img[^>]+?src=[\"']?([^>'\"]+)[\"']?";

方法二:通过webview和js 本地程序的交换,获取到html页面所有图片下载地址。
webview和本地程序交互的方法是_detailWebView stringByEvaluatingJavaScriptFromString。
这是方法二获取图片url的js代码如下:

 
1
2
3
4
5
6
7
8
9
10
11
//获取web里的所有的img url
- (NSString *)createImgArrayJavaScript{
    NSString *js = @"var imgArray = document.getElementsByTagName('img'); var imgstr = ''; function f(){ for(var i = 0; i < imgArray.length; i++){ imgstr += imgArray[i].src;imgstr += ';';} return imgstr; } f();";
    return js;
}
 
//返回web img图片的数量
- (NSString *)createGetImgNumJavaScript{
    NSString *js = @"var imgArray = document.getElementsByTagName('img');function f(){ var num=imgArray.length;return num;} f();";
    return js;
}

第2步、把下载图片到本地,把本地的图片设置到html代码中去显示。
通过上面说的两个方法,你可以获取到图片地址了并且能下载到本地了。那没网络的情况下怎么把这些图片再设置到html页面里呢?
方法:下载到本地的图片命名一律使用图片url的md5。因为url直接做不了图片的名称。 
下面这段代码演示了下载图片和设置本地图片的全过程。代码的逻辑是:有本地图片,就显示本地图片,如果没有则从网络获取。还有对应的js代码。设置图片是还判断图片的宽度,大于300时,就等比例缩小。

 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
- (void)downLoadImageFromURL:(NSArray* )imageUrlArray
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_group_t group = dispatch_group_create();
     
    for (int i = 0; i < imageUrlArray.count; i++)
    {
        NSString *imageUrl = [imageUrlArray objectAtIndex:i];
        NSString *key = [imageUrl MD5Hash];
        NSData *data = [FTWCache objectForKey:key];
        NSURL *imageURL = [NSURL URLWithString:imageUrl];
        NSString *index = [NSString stringWithFormat:@"%d", i];
 
        if (data) {
            [_detailWebView stringByEvaluatingJavaScriptFromString:[self createSetImageUrlJavaScript:index
                                                                                              imgUrl:key]];
             
        }else{
            dispatch_group_async(group, queue, ^{
             NSData *data = [NSData dataWithContentsOfURL:imageURL];
             if (data != nil) {
                 [FTWCache setObject:data forKey:key];
                 dispatch_sync(dispatch_get_main_queue(), ^{
                     [_detailWebView stringByEvaluatingJavaScriptFromString:[self createSetImageUrlJavaScript:index
                                                                                                       imgUrl:key]];
                      
                     
                     DDLOG(@"image i %d",i);
                 });
                   
             }
        });
         
        }
    }
     
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        //这里是所有图片下载完成后执行的操作。
    });
     
    dispatch_release(group);
}
 
//设置下载完成的图片到web img
- (NSString *)createSetImageUrlJavaScript:(NSString *) index imgUrl:(NSString *) url{
    NSData *imageData = [FTWCache objectForKey:url];
    UIImage  *image = [UIImage imageWithData:imageData];
    int imageWidth = 300;
    int imageHeight = image.size.height*300.0f/image.size.width;
    NSString *js = [NSString stringWithFormat:@"var imgArray = document.getElementsByTagName('img'); imgArray[%@].src=\"%@\"; imgArray[%@].width=\"%d\";imgArray[%@].height=\"%d\" ;" , index, url, index,imageWidth,index,imageHeight];
    return js;
}
 
完整的通过正则获取html代码中的所有图片url的代码如下:
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (void) getImageUrlArray:(NSString*) content
{
    DDLOG_CURRENT_METHOD;
    NSString *urlPattern = @"<img[^>]+?src=[\"']?([^>'\"]+)[\"']?";
    NSError *error = [NSError new];
     
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:urlPattern options:NSRegularExpressionCaseInsensitive error:&error ];
     
    //match 这块内容非常强大
    NSUInteger count =[regex numberOfMatchesInString:content options:NSRegularExpressionCaseInsensitive range:NSMakeRange(0, [content length])];//匹配到的次数
    if(count > 0){
        NSArray* matches = [regex matchesInString:content options:NSMatchingReportCompletion range:NSMakeRange(0, [content length])];
         
        for (NSTextCheckingResult *match in matches) {
             
            NSInteger count = [match numberOfRanges];//匹配项
            for(NSInteger index = 0;index < count;index++){
                NSRange halfRange = [match rangeAtIndex:index];
                if (index == 1) {
                    [listImage addObject:[content substringWithRange:halfRange]];
                }
            }
        }//遍历后可以看到三个range,1、为整体。2、为([\\w-]+\\.)匹配到的内容。3、(/?[\\w./?%&=-]*)匹配到的内容
    }
 
}
 

方式二:NSURLProtocol缓存

可能很多人使用过UIWebView,也考虑过如何在离线状态下读取缓存的问题,但是好像没有一个标准的答案。有的人说可以,有的人说不行。通过这几天的研究,我发现了一些问题,在这里希望各位给点意见。

另外,还要求助一下,有没有人知道在ios上测试网页加载速度的工具啊? 找了好久都没看到。最好是免费的。
一.HTML5 , Manifest
最开始我的想法是使用HTML5中的离线存储功能,也就是分析Manifest文件来存储和更新部分资源文件。但是经过实践发现,UIWebView根本不支持HTML5,他只实现了Webkit中页面渲染的那一部分。所以要实现缓存必须要另辟蹊径。

二.ASIHTTPRequest,ASIDownloadCache  和 ASIWebPageRequest
   首先我得说,这确实是个很好的框架,使用起来确实很方便,但是对于缓存这个问题,好像也跟第二点提到的效果差不多,加载速度没有明显的提升,离线模式下也无法加载。这是实现的代码

  1. -(void)loadURL:(NSURL*)url
  2. {
  3. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
  4. //ASIWebPageRequest *request= [ASIWebPageRequest requestWithURL:url];
  5. [request setDelegate:self];
  6. //[request setUrlReplacementMode:ASIReplaceExternalResourcesWithData];
  7. [request setDidFailSelector:@selector(webPageFetchFailed:)];
  8. [request setDidFinishSelector:@selector(webPageFetchSucceeded:)];
  9. //设置缓存
  10. [request setDownloadCache:[ASIDownloadCache sharedCache]];
  11. //[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
  12. [request setCachePolicy:ASIAskServerIfModifiedWhenStaleCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy];
  13. [request setDownloadDestinationPath:[[ASIDownloadCache sharedCache]pathToStoreCachedResponseDataForRequest:request]];
  14. [request startAsynchronous];
  15. }
  16. - (void)webPageFetchFailed:(ASIHTTPRequest *)theRequest
  17. {
  18. // Obviously you should handle the error properly...
  19. NSLog(@"%@",[theRequest error]);
  20. NSString *path = [[NSBundle mainBundle] pathForResource:@"error1.html" ofType:nil inDirectory:@"WebResources/Error"];
  21. NSURL  *url=[NSURL fileURLWithPath:path];
  22. [viewer loadRequest:[NSURLRequest requestWithURL:url]];
  23. }
  24. - (void)webPageFetchSucceeded:(ASIHTTPRequest *)theRequest
  25. {
  26. NSString *response = [NSString stringWithContentsOfFile:
  27. [theRequest downloadDestinationPath] encoding:[theRequest responseEncoding] error:nil];
  28. // Note we're setting the baseURL to the url of the page we downloaded. This is important!
  29. [viewer loadHTMLString:response baseURL:[theRequest url]];
  30. //[viewer loadHTMLString:response baseURL:nil];
  31. }
三.NSURLCache

尽管在官方的说明文档里面说到NSURLCache和NSCachedURLResponse可以用于缓存,但经我测试好像仅仅只能用于加载本地某些资源文件(这里有一篇博客,原文是英文的,这是翻译过来的
,而且还有大小的限制(好像根据iphone的版本不同而不同,最小是25KB吧),比如图片和JS代码, 而对于整体的页面无法进行加载。而且经过测试也没有感觉加载速度有明显的提高,我用的缓存策略是NSURLRequestReturnCacheDataElseLoad(可能是没有读取本地的缓存文件?),离线模式下也无法加载(可能是baseURL的关系?)。
这找到一篇博客,一种新的解决思路,经过我测试,可以很好的实现缓存。
另外做一点引申,对于动态获取数据的页面,我们不需要缓存的那些请求,只要过滤掉就可以了。
先新建一个文件,把所有不需要缓存的请求的URL写在一个文件里,就象HTML5的 Cache Manifest那样。
然后需要使用缓存的时候读取这个文件,并在重写的- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request  这个方法内对请求进行判断,如果是属于这个文件内的,比如web service的请求就直接返回,其他的就继续处理。

 
四.利用NSURLProtocol实现离线缓存(推荐 对于一般简单缓存)
 

搜索解决方案的时候找到了Rob Napier 的博文:Drop-in offline caching for UIWebView (and NSURLProtocol) 文章介绍了使用NSURLProtocol实现UIWebView的离线缓存的简单实现,你可以在github上下载这个demo的代码。

rob认为无论是“MKNetworkKit”还是”AFCache”实现的缓存都过于复杂,而他想要的是一个简单机制:

1、你使用了UIWebView指向来显示一个有图像嵌入的网站。
2、当你的设备online时,你有正常的缓存算法。
3、当你的设备offline时,你可以显示页面的最后一个版本。

这个demo里做了一个很简单的测试:将cnn.com运行一次,然后再将网络断掉,去浏览这些数据。

现有解决方案:

Matt Gallagher 有一些有趣的想法,使用NSURLCache的子类来实现,但是Rob发现这是不可靠的,尤其是iOS5的HTTP缓存规则十分复杂,在许多情况下如果你不访问服务器便不能获知你缓存的数据是否有效。另外,一些必要的素材如果没有被缓存,那么在离线时前期做的缓存工作就实效了。(辉:NSURLCache实现离线阅读的一点小心得 我也曾讨论了一些相关问题)

AFCache也被认为是一个很好的解决方案(辉:有时间我会对这个开源库进行详细评估,表面上看就是connection、NSURLCache、NSURLProtocol的综合解决方案)。短时间内作者并没有使测试通过,但是AFCache的作者也在文章后边回复说,采纳了Rob的想法,已经提交代码到github上。

要点:
1、尽早注册你的URLProtocol(application:didFinishLaunchingWithOptions:)。
2、NSURLProtocol是NSURLConnection的handler。NSURLConnection的每个请求都会去便利所有的Protocols,并询问你能处理这个请求么(canInitWithRequest: )。如果这个Protocol返回YES,则第一个返回YES的Protocol会来处理这个connection。Protocols的遍历是反向的,也就是最后注册的Protocol会被优先判断。
3、 当你的handler被选中了,connection就会调用–> initWithRequest:cachedResponse:client:,紧接着会调用–>startLoading。然后你需要负责回调:–>URLProtocol:didReceiveResponse:cacheStoragePolicy:,有些则会调用:–>URLProtocol:didLoadData:, 并且最终会调用–>URLProtocolDidFinishLoading:。你有没有发现这些方法和NSURLConnection delegate的方法非常类似——这绝非偶然!
4、当online的情况下,RNCachingURLProtocol只是负责将请求转发给一个新的NSURLConnection,并且拷贝一份结果给原来的connection。offline时, RNCachingURLProtocol就会从磁盘里载入先前的结果,并将这些数据发回给连接。整个过程只有区区200行代码(不包含Reachability)。
5、这里还有一个有趣的问题,就是当RNCachingURLProtocol创建了一个新的NSURLConnection的,即新的connection也会去找一个handler。 如果RNCachingURLProtocol说可以处理,那么就死循环了。怎么解决呢?通过添加自定义HTTP Header(X-RNCache)来标记这个请求,告诉RNCachingURLProtocol不要再处理这个请求。
6、它可以响应所有的connection,所以你可能需要修改canInitWithRequest:来 选择你要缓存的数据。

另外:并发请求或复杂网络请求的缓存请使用MKNetworkKit(我们也在一个项目中使用了这个类库,非常轻量快捷是ASI的很不错的替代品)。

总结一下:
这项技术不是用来替代AFCache、MKNetworkKit的,他只是用来解决独立的、简单问题的(当然它也可以通过复杂实现来解决复杂问题)。 NSURLProtocol是非常强大的,Rob已经使用它来监听网络流量(如PandoraBoy中的几个ProxyURLProtocol类)。它非常值得你将其添加到你的工具箱中。

实例代码下载

#方式二还有某技术人员分享的代码如下

//WebCachedData.h
#import <Foundation/Foundation.h> static NSUInteger const kCacheExpireTime = ;//缓存的时间 默认设置为600秒 @interface WebCachedData :NSObject <NSCoding>
@property (nonatomic,strong) NSData *data;
@property (nonatomic,strong) NSURLResponse *response;
@property (nonatomic,strong) NSURLRequest *redirectRequest;
@property (nonatomic,strong) NSDate *date;
@end //WebCachedData.m
#import "WebCachedData.h" static NSString *const kDataKey =@"data";
static NSString *const kResponseKey =@"response";
static NSString *const kRedirectRequestKey =@"redirectRequest";
static NSString *const kDateKey =@"date"; @implementation WebCachedData - (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:[self data] forKey:kDataKey];
[aCoder encodeObject:[self response] forKey:kResponseKey];
[aCoder encodeObject:[self redirectRequest] forKey:kRedirectRequestKey];
[aCoder encodeObject:[self date] forKey:kDateKey];
} - (id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self !=nil) {
[self setData:[aDecoder decodeObjectForKey:kDataKey]];
[self setResponse:[aDecoder decodeObjectForKey:kResponseKey]];
[self setRedirectRequest:[aDecoder decodeObjectForKey:kRedirectRequestKey]];
[self setDate:[aDecoder decodeObjectForKey:kDateKey]];
} return self;
} @end //CacheURLProtocol.h
#import <Foundation/Foundation.h>
#import "WebCachedData.h" @interface CacheURLProtocol : NSURLProtocol @end //CacheURLProtocol.m
#import "CacheURLProtocol.h"
#import <CommonCrypto/CommonDigest.h> static NSString *const kOurRecursiveRequestFlagProperty =@"COM.WEIMEITC.CACHE";
static NSString *const kSessionQueueName =@"WEIMEITC_SESSIONQUEUENAME";
static NSString *const kSessionDescription =@"WEIMEITC_SESSIONDESCRIPTION"; @interface CacheURLProtocol()<NSURLSessionDataDelegate> @property (nonatomic,strong) NSURLSession *session;
@property (nonatomic,copy) NSURLSessionConfiguration *configuration;
@property (nonatomic,strong) NSOperationQueue *sessionQueue;
@property (nonatomic,strong) NSURLSessionDataTask *task;
@property (nonatomic,strong) NSMutableData *data;
@property (nonatomic,strong) NSURLResponse *response; - (void)appendData:(NSData *)newData;
@end @implementation CacheURLProtocol static NSObject *CacheURLProtocolIgnoreURLsMonitor;
static NSArray *CacheURLProtocolIgnoreURLs; + (BOOL)registerProtocolWithIgnoreURLs:(NSArray*)ignores {
[self unregisterCacheURLProtocol];
[self setIgnoreURLs:ignores];
return [[self class] registerClass:[self class]];
} + (void)unregisterCacheURLProtocol {
[self setIgnoreURLs:nil];
[[self class] unregisterClass:[self class]];
} - (void)dealloc {
[self.task cancel]; [self setTask:nil];
[self setSession:nil];
[self setData:nil];
[self setResponse:nil];
[self setSessionQueue:nil];
[self setConfiguration:nil];
[[self class] setIgnoreURLs:nil];
} +(void)initialize {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
CacheURLProtocolIgnoreURLsMonitor = [NSObject new];
});
} #pragma mark - URLProtocol APIs
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
// 可以修改request对象
return request;
} + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
return [super requestIsCacheEquivalent:a toRequest:b];
} + (BOOL)canInitWithTask:(NSURLSessionTask *)task {
return [self canInitWithURLRequest:task.currentRequest];
} - (instancetype)initWithTask:(NSURLSessionTask *)task cachedResponse:(nullable NSCachedURLResponse *)cachedResponse client:(nullable id <NSURLProtocolClient>)client { self = [super initWithTask:task cachedResponse:cachedResponse client:client];
if (self !=nil) {
[self configProtocolParam];
}
return self;
} + (BOOL)canInitWithRequest:(NSURLRequest *)request {
return [self canInitWithURLRequest:request];
} - (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id <NSURLProtocolClient>)client { self = [super initWithRequest:request cachedResponse:cachedResponse client:client];
if (self !=nil) {
[self configProtocolParam];
}
return self;
} - (void)startLoading { WebCachedData *cache = [NSKeyedUnarchiver unarchiveObjectWithFile:[self cachePathForRequest:[self request]]]; // 这地方不能判断cache.data字段,有可能是一个重定向的request
if (cache) {
// 本地有缓存
NSData *data = [cache data]; NSURLResponse *response = [cache response];
NSURLRequest *redirectRequest = [cache redirectRequest];
NSDate *date = [cache date];
if ([self expireCacheData:date]) {
// 数据过期
NSLog(@"request Data-expire!");
NSMutableURLRequest *recursiveRequest = [[self request] mutableCopy];
[[self class] setProperty:@(YES) forKey:kOurRecursiveRequestFlagProperty inRequest:recursiveRequest];
self.task = [self.session dataTaskWithRequest:recursiveRequest];
[self.task resume]; } else {
if (redirectRequest) {
[[self client] URLProtocol:self wasRedirectedToRequest:redirectRequest redirectResponse:response];
} else { if (data) {
NSLog(@"cached Data!");
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
} else {
// 本地没有缓存上data
NSLog(@"request Data-uncached data!");
NSMutableURLRequest *recursiveRequest = [[self request] mutableCopy];
[[self class] setProperty:@YES forKey:kOurRecursiveRequestFlagProperty inRequest:recursiveRequest];
self.task = [self.session dataTaskWithRequest:recursiveRequest];
[self.task resume];
}
}
} } else { // 本地无缓存
NSLog(@"request Data-no data!");
NSMutableURLRequest *recursiveRequest = [[self request] mutableCopy];
[[self class] setProperty:@YES forKey:kOurRecursiveRequestFlagProperty inRequest:recursiveRequest];
self.task = [self.session dataTaskWithRequest:recursiveRequest];
[self.task resume];
}
} - (void)stopLoading {
[self.task cancel]; [self setTask:nil];
[self setData:nil];
[self setResponse:nil];
} #pragma mark - NSURLSession delegate - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)newRequest completionHandler:(void (^)(NSURLRequest *))completionHandler { if (response !=nil) {
NSMutableURLRequest *redirectableRequest = [newRequest mutableCopy];
[[self class] removePropertyForKey:kOurRecursiveRequestFlagProperty inRequest:redirectableRequest]; NSString *cachePath = [self cachePathForRequest:[self request]];
WebCachedData *cache = [[WebCachedData alloc] init];
[cache setResponse:response];
[cache setData:[self data]];
[cache setDate:[NSDate date]];
[cache setRedirectRequest:redirectableRequest];
[NSKeyedArchiver archiveRootObject:cache toFile:cachePath]; [[self client] URLProtocol:self wasRedirectedToRequest:redirectableRequest redirectResponse:response]; [self.task cancel];
[[self client] URLProtocol:self didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]]; completionHandler(redirectableRequest);
} else {
completionHandler(newRequest);
}
} - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void(^)(NSURLSessionResponseDisposition))completionHandler { [self setResponse:response];
[self setData:nil];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; completionHandler(NSURLSessionResponseAllow);
} - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { [[self client] URLProtocol:self didLoadData:data];
[self appendData:data];
} - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)dataTask didCompleteWithError:(NSError *)error { if (error ) {
[self.client URLProtocol:self didFailWithError:error];
} else {
NSString *cachePath = [self cachePathForRequest:[self request]];
WebCachedData *cache = [[WebCachedData alloc] init];
[cache setResponse:[self response]];
[cache setData:[self data]];
[cache setDate:[NSDate date]];
[NSKeyedArchiver archiveRootObject:cache toFile:cachePath]; [[self client] URLProtocolDidFinishLoading:self];
}
} #pragma mark - private APIs + (NSArray *)ignoreURLs {
NSArray *iURLs;
@synchronized(CacheURLProtocolIgnoreURLsMonitor) {
iURLs = CacheURLProtocolIgnoreURLs;
}
return iURLs;
} + (void)setIgnoreURLs:(NSArray *)iURLs {
@synchronized(CacheURLProtocolIgnoreURLsMonitor) {
CacheURLProtocolIgnoreURLs = iURLs;
}
} + (BOOL)canInitWithURLRequest:(NSURLRequest*)request { // 过滤掉不需要走URLProtocol
NSArray *ignores = [self ignoreURLs];
for (NSString *url in ignores) {
if ([[request.URL absoluteString] hasPrefix:url]) {
return NO;
}
} // 如果是startLoading里发起的request忽略掉,避免死循环
BOOL recurisve = [self propertyForKey:kOurRecursiveRequestFlagProperty inRequest:request] == nil; // 没有标识位kOurRecursiveRequestFlagProperty的并且是以http开的scheme都走代理;
if (recurisve && [[request.URL scheme] hasPrefix:@"http"]) {
return YES;
} return NO;
} - (void)configProtocolParam {
NSURLSessionConfiguration *config = [[NSURLSessionConfiguration defaultSessionConfiguration] copy];
[config setProtocolClasses:@[ [self class] ]];
[self setConfiguration:config]; NSOperationQueue *q = [[NSOperationQueue alloc] init];
[q setMaxConcurrentOperationCount:];
[q setName:kSessionQueueName];
[self setSessionQueue:q]; NSURLSession *s = [NSURLSession sessionWithConfiguration:_configuration delegate:self delegateQueue:_sessionQueue];
s.sessionDescription =kSessionDescription;
[self setSession:s];
} - (NSString*)md5Encode:(NSString*)srcString {
const char *cStr = [srcString UTF8String];
unsigned char result[];
CC_MD5( cStr, (unsigned int)strlen(cStr), result); NSString *formatString =@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"; return [NSString stringWithFormat:formatString,
result[], result[], result[], result[],
result[], result[], result[], result[],
result[], result[], result[], result[],
result[], result[], result[], result[]];
} - (NSString *)cachePathForRequest:(NSURLRequest *)aRequest {
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES)lastObject];
NSString *fileName = [self md5Encode:[[aRequest URL]absoluteString]];
return [cachesPath stringByAppendingPathComponent:fileName];
} - (void)appendData:(NSData *)newData {
if ([self data] == nil) {
self.data = [[NSMutableData alloc] initWithCapacity:];
} if (newData) {
[[self data] appendData:newData];
}
} - (BOOL)expireCacheData:(NSDate *)date { if (!date) {
return YES;
} NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:date];
BOOL bRet = timeInterval <kCacheExpireTime;
if (!bRet) {
// 过期删除缓存
NSString *filename = [self cachePathForRequest:[self request]];
NSFileManager *defaultManager = [NSFileManager defaultManager];
if ([defaultManager isDeletableFileAtPath:filename]) {
[defaultManager removeItemAtPath:filename error:nil];
}
} return !bRet;
} @end

他山之石

 
链接:
 
iOS开发之--- NSURLProtocol(截取request请求)

iOS关于html缓存的更多相关文章

  1. iOS之 清理缓存

    作为一个开发者,对于缓存的清理也是理所应当的需要的.这次就简单的谈一下iOS中对于缓存的清理方法. 我们清理缓存通常是在这三种方式下进行的: (1)项目中的清理缓存按钮 (2)点击退出app按钮时清理 ...

  2. iOS中dyld缓存的实现原理是怎样的?

    在iOS开发中,为了提升系统的安全性,很多系统库文件都被打包到一个缓存的文件当中即dyld缓存,那大家对dyld缓存了解多少呢?今天小编将和大家分享的就是一位iOS大神对dyld缓存的使用分析,一起来 ...

  3. 玩转iOS开发 - 数据缓存

    Why Cache 有时候.对同一个URL请求多次,返回的数据可能都是一样的,比方server上的某张图片.不管下载多少次,返回的数据都是一样的. 上面的情况会造成下面问题 (1)用户流量的浪费 (2 ...

  4. iOS html5使用缓存并及时更新方案总结

    最近一段时间研究了一下H5在iOS移动端表现时使用缓存并可及时更新方案,总结如下: 一.使用Webview自带缓存机制 当我们使用webview加载html资源时的,本质上就是一个向服务器索取资源的h ...

  5. iOS开发网络缓存原理

    一.关于同一个URL的多次请求 有时候,对同一个URL请求多次,返回的数据可能都是一样的,比如服务器上的某张图片,无论下载多少次,返回的数据都是一样的. 上面的情况会造成以下问题 (1)用户流量的浪费 ...

  6. iOS 清理文件缓存

    本文摘自:<msp的昌伟哥哥-iOS开发-清理缓存功能的实现>摘下来的目的就是为了能够学习.还望看到文章的同学,前往原创的博客园.感谢msp的昌伟哥哥的分享精神. 移动应用在处理网络资源时 ...

  7. IOS中无缓存的图片载入

    在IOS中,我们常用[UIImage imageNamed]方法获取图像,这种方法简便,容易理解.但是有个缺点,就是有缓存.这种方式 传人的图像的就是通过文件名方式文件名.如果,我们内存有限,我们就必 ...

  8. iOS - ImageCache 网络图片缓存

    1.ImageCache 使用内存缓存方式: 使用沙盒缓存方式: 使用网络图片第三方库方式: SDWebImage: iOS 中著名的网络图片处理框架 包含的功能:图片下载.图片缓存.下载进度监听.g ...

  9. ios开发--清理缓存

    ios文章原文 一段清理缓存的代码如下: dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) , ...

随机推荐

  1. Eclipse的自动排版设置(format)

    Java排版:         主要是在文件保存时自动触发排版等规则,省掉反复操作快捷键 Ctrl+Shift+F 的步骤.在 eclipse 中选择 Window-> Preferences- ...

  2. 统计整个Xcode工程代码行数

    打开终端,ls 查看目录,用cd命令 定位到工程所在的目录,然后调用以下命名即可把每个源代码文件行数及总数统计出来: find . "(" -name "*.m" ...

  3. WPF 命令基础

    1命令的组成 命令源:就是谁发送的命令. 命令目标:就是这个命令发送给谁,谁接受的命令. 命令:就是命令的内容. 命令关联:就是把命令和外围的逻辑关联起来,主要用来判断命令是否可以执行和执行完以后干点 ...

  4. 悟语 KISS 简单至上 keep it simple stupid

    引自 PostgreSQL Server Programming-Second Edition page81: 大部分时候,我们不需要快速的代码,而是能用的程序. remember that most ...

  5. java的反射机制

    一.java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动, ...

  6. Tomcat:云环境下的Tomcat设计思路——Tomcat的多实例安装

    Cloud现在是一个热门的技术,Tomcat是学习Java的人一般都会接触的Web服务器,如果在Cloud环境下使用Tomcat,又当如何呢?不可避免的,要安装多个Tomcat了,这里称之为Tomca ...

  7. Mysql Error:1205错误诊断

    前两天遇到一个1205(ER_LOCK_WAIT_TIMEOUT)的错误,弄了半天终于找到原因,掌握原理+细心才能找到罪归祸首.下面我给大家分享下这个问题的分析处理过程,希望对大家有所帮助.接到sla ...

  8. 十五天精通WCF——终结篇 那些你需要注意的坑

    终于一路走来,到了本系列的最后一篇了,这一篇也没什么好说的,整体知识框架已经在前面的系列文章中讲完了,wcf的配置众多,如果 不加一些指定配置,你可能会遇到一些灾难性的后果,快来一睹为快吧. 一: 第 ...

  9. 记一次使用openrowset 的坑

    前几天被老大训斥连openrowset 都不会用,然后我就去看了文档,想测试一下栗子~ openrowset 的具体语法我就不贴了,戳这里:https://msdn.microsoft.com/zh- ...

  10. W3School-CSS测验

    The only way to survive was to enjoy the good moments and not dwell too much on the bad. 生活,就应该享受美好的 ...