iOS之网页缓存html----NSURLCache-----NSURLProtocol

2024-05-31 10:32

本文主要是介绍iOS之网页缓存html----NSURLCache-----NSURLProtocol,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

实现网页缓存的方法:
MKNetworkKit
AFCache”实现的缓存
NSMURLCache
NSURLProtocol




网页缓存:

//写入缓存

- (void)writeToCache

{

    NSString * htmlResponseStr = [NSString stringWithContentsOfURL:self.url encoding:NSUTF8StringEncoding error:Nil];

    //创建文件管理器

    NSFileManager *fileManager = [NSFileManagerdefaultManager];

    //获取document路径

    NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)objectAtIndex:0];

    [fileManager createDirectoryAtPath:[cachesPathstringByAppendingString:@"/Caches"]withIntermediateDirectories:YESattributes:nilerror:nil];

    //写入路径

    NSString * path = [cachesPath stringByAppendingString:[NSString stringWithFormat:@"/Caches/%lu.html",(unsignedlong)[[self.url absoluteString] hash]]];

    

    [htmlResponseStr writeToFile:pathatomically:YESencoding:NSUTF8StringEncodingerror:nil];

}


======
取出缓存:

//有缓存就加载缓存,没缓存就从服务器加载

- (void)viewDidLoad

{

    NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)objectAtIndex:0];

    NSString * path = [cachesPath stringByAppendingString:[NSString stringWithFormat:@"/Caches/%lu.html",(unsignedlong)[[self.url absoluteString] hash]]];

    NSString *htmlString = [NSStringstringWithContentsOfFile:pathencoding:NSUTF8StringEncodingerror:nil];

    

    if (!(htmlString ==nil || [htmlStringisEqualToString:@""])) {

        [self.webView loadHTMLString:htmlString baseURL:self.url];

    }else{

        

        NSURLRequest *request = [NSURLRequest requestWithURL:self.url];

        [_webView loadRequest:request];

        [self writeToCache];

    }

}


HTML缓存参考:http://www.cnblogs.com/On1Key/p/5756747.html
==========NSURLCache缓存网页=======

为了减少流量开销,离线浏览也就成了很关键的功能,而UIWebView这个让人又爱又恨的玩意弱爆了,居然只在Mac OS X上提供webView:resource:willSendRequest:redirectResponse:fromDataSource:这个方法,于是只好自己动手实现了。

原理就是SDK里绝大部分的网络请求都会访问[NSURLCache sharedURLCache]这个对象,它的cachedResponseForRequest:方法会返回一个NSCachedURLResponse对象。如果这个NSCachedURLResponse对象不为nil,且没有过期,那么就使用这个缓存的响应,否则就发起一个不访问缓存的请求。
要注意的是NSCachedURLResponse对象不能被提前释放,除非UIWebView去调用NSURLCache的removeCachedResponseForRequest:方法,原因貌似是UIWebView并不retain这个响应。而这个问题又很头疼,因为UIWebView有内存泄露的嫌疑,即使它被释放了,也很可能不去调用上述方法,于是内存就一直占用着了。

顺便说下NSURLRequest对象,它有个cachePolicy属性,只要其值为NSURLRequestReloadIgnoringLocalCacheData的话,就不会访问缓存。可喜的是这种情况貌似只有在缓存里没取到,或是强制刷新时才可能出现。
实际上NSURLCache本身就有磁盘缓存功能,然而在iOS上,NSCachedURLResponse却被限制为不能缓存到磁盘(NSURLCacheStorageAllowed被视为NSURLCacheStorageAllowedInMemoryOnly)。
不过既然知道了原理,那么只要自己实现一个NSURLCache的子类,然后改写cachedResponseForRequest:方法,让它从硬盘读取缓存即可。
========

#import <UIKit/UIKit.h>


@interface ViewController :UIViewController <UIWebViewDelegate>


@property(nonatomic,retain)UIWebView *webView;


@end


=========

#import "ViewController.h"

#import "CustomURLCache.h"

#import "MBProgressHUD.h"


@interface ViewController ()


@end


@implementation ViewController


@synthesize webView = _webView;


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {

    if (self = [superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil]) {

        CustomURLCache *urlCache = [[CustomURLCachealloc]initWithMemoryCapacity:20 * 1024 * 1024

                                                                    diskCapacity:200 * 1024 * 1024

                                                                        diskPath:nil

                                                                       cacheTime:0];

        [CustomURLCachesetSharedURLCache:urlCache];

        [urlCache release];

    }

    returnself;

}


- (void)viewDidLoad {

    [superviewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

    

    UIWebView *webView = [[UIWebViewalloc]initWithFrame:self.view.frame];

    webView.delegate =self;

    self.webView = webView;

    [webView release];

    [self.viewaddSubview:_webView];

    

    [self.webViewloadRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.baidu.com/"]]];

}


- (void)didReceiveMemoryWarning

{

    [superdidReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

    

    CustomURLCache *urlCache = (CustomURLCache *)[NSURLCachesharedURLCache];

    [urlCache removeAllCachedResponses];

}


- (void)dealloc {

    [_webViewrelease];

    [superdealloc];

}


#pragma mark - webview


- (void)webViewDidFinishLoad:(UIWebView *)webView {

    [MBProgressHUDhideHUDForView:self.viewanimated:YES];

}


- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {

    [MBProgressHUDhideHUDForView:self.viewanimated:YES];

}


- (void)webViewDidStartLoad:(UIWebView *)webView {

    MBProgressHUD *hud = [MBProgressHUDshowHUDAddedTo:self.viewanimated:YES];

    hud.mode =MBProgressHUDModeIndeterminate;

    hud.labelText =@"Loading...";

}


@end


============

#import <Foundation/Foundation.h>

#import "Util.h"


@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

=========

#import "CustomURLCache.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;


- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path cacheTime:(NSInteger)cacheTime {

    if (self = [selfinitWithMemoryCapacity:memoryCapacitydiskCapacity:diskCapacitydiskPath:path]) {

        self.cacheTime = cacheTime;

        if (path)

            self.diskPath = path;

        else

            self.diskPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];

        

        self.responseDictionary = [NSMutableDictionarydictionaryWithCapacity:0];

    }

    returnself;

}


- (void)dealloc {

    [_diskPathrelease];

    [_responseDictionaryrelease];

    [superdealloc];

}

原理就是SDK里绝大部分的网络请求都会访问[NSURLCache sharedURLCache]这个对象,它的cachedResponseForRequest:方法会返回一个NSCachedURLResponse对象。如果这个NSCachedURLResponse对象不为nil,且没有过期,那么就使用这个缓存的响应,否则就发起一个不访问缓存的请求。

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {

    if ([request.HTTPMethodcompare:@"GET"] !=NSOrderedSame) {

        return [supercachedResponseForRequest:request];

    }

    

    return [selfdataFromRequest:request];

}


- (void)removeAllCachedResponses {

    [superremoveAllCachedResponses];

    

    [selfdeleteCacheFolder];

}


- (void)removeCachedResponseForRequest:(NSURLRequest *)request {

    [superremoveCachedResponseForRequest:request];

    

    NSString *url = request.URL.absoluteString;

    NSString *fileName = [selfcacheRequestFileName:url];

    NSString *otherInfoFileName = [selfcacheRequestOtherInfoFileName:url];

    NSString *filePath = [selfcacheFilePath:fileName];

    NSString *otherInfoPath = [selfcacheFilePath:otherInfoFileName];

    NSFileManager *fileManager = [NSFileManagerdefaultManager];

    [fileManager removeItemAtPath:filePatherror:nil];

    [fileManager removeItemAtPath:otherInfoPatherror:nil];

}


#pragma mark - custom url cache


- (NSString *)cacheFolder {

    return@"URLCACHE";

}


- (void)deleteCacheFolder {

    NSString *path = [NSStringstringWithFormat:@"%@/%@",self.diskPath, [selfcacheFolder]];

    NSFileManager *fileManager = [NSFileManagerdefaultManager];

    [fileManager removeItemAtPath:patherror:nil];

}


- (NSString *)cacheFilePath:(NSString *)file {

    NSString *path = [NSStringstringWithFormat:@"%@/%@",self.diskPath, [selfcacheFolder]];

    NSFileManager *fileManager = [NSFileManagerdefaultManager];

    BOOL isDir;

    if ([fileManagerfileExistsAtPath:pathisDirectory:&isDir] && isDir) {

        

    } else {

        [fileManager createDirectoryAtPath:pathwithIntermediateDirectories:YESattributes:nilerror:nil];

    }

    return [NSStringstringWithFormat:@"%@/%@", path, file];

}


- (NSString *)cacheRequestFileName:(NSString *)requestUrl {

    return [Utilmd5Hash:requestUrl];

}


- (NSString *)cacheRequestOtherInfoFileName:(NSString *)requestUrl {

    return [Utilmd5Hash:[NSStringstringWithFormat:@"%@-otherInfo", requestUrl]];

}


- (NSCachedURLResponse *)dataFromRequest:(NSURLRequest *)request {

    NSString *url = request.URL.absoluteString;

    NSString *fileName = [selfcacheRequestFileName:url];

    NSString *otherInfoFileName = [selfcacheRequestOtherInfoFileName:url];

    NSString *filePath = [selfcacheFilePath:fileName];

    NSString *otherInfoPath = [selfcacheFilePath:otherInfoFileName];

    NSDate *date = [NSDatedate];

    

    NSFileManager *fileManager = [NSFileManagerdefaultManager];

    if ([fileManagerfileExistsAtPath:filePath]) {

        BOOL expire =false;

        NSDictionary *otherInfo = [NSDictionarydictionaryWithContentsOfFile:otherInfoPath];

        

        if (self.cacheTime > 0) {

            NSInteger createTime = [[otherInfoobjectForKey:@"time"]intValue];

            if (createTime +self.cacheTime < [datetimeIntervalSince1970]) {

                expire = true;

            }

        }

        

        if (expire ==false) {

            NSLog(@"data from cache ...");

            

            NSData *data = [NSDatadataWithContentsOfFile:filePath];

            NSURLResponse *response = [[NSURLResponsealloc]initWithURL:request.URL

                                                                MIMEType:[otherInfo objectForKey:@"MIMEType"]

                                                   expectedContentLength:data.length

                                                        textEncodingName:[otherInfoobjectForKey:@"textEncodingName"]];

            NSCachedURLResponse *cachedResponse = [[[NSCachedURLResponsealloc]initWithResponse:responsedata:data]autorelease];

            [response release];

            return cachedResponse;

        } else {

            NSLog(@"cache expire ... ");

            

            [fileManager removeItemAtPath:filePatherror:nil];

            [fileManager removeItemAtPath:otherInfoPatherror:nil];

        }

    }

    

    __blockNSCachedURLResponse *cachedResponse =nil;

    //sendSynchronousRequest请求也要经过NSURLCache

    id boolExsite = [self.responseDictionaryobjectForKey:url];

    if (boolExsite ==nil) {

        [self.responseDictionarysetValue:[NSNumbernumberWithBool:TRUE]forKey:url];

  

        [NSURLConnectionsendAsynchronousRequest:requestqueue:[[NSOperationQueuealloc]init]completionHandler:^(NSURLResponse *response,NSData *data,NSError *error)

        {

            [self.responseDictionaryremoveObjectForKey:url];

            

            if (error) {

                NSLog(@"error : %@", error);

                NSLog(@"not cached: %@", request.URL.absoluteString);

                cachedResponse = nil;

            }

            

            NSLog(@"get request ... ");

            

            //save to cache

            NSDictionary *dict = [NSDictionarydictionaryWithObjectsAndKeys:[NSStringstringWithFormat:@"%f", [datetimeIntervalSince1970]],@"time",

                                  response.MIMEType,@"MIMEType",

                                  response.textEncodingName,@"textEncodingName",nil];

            [dict writeToFile:otherInfoPathatomically:YES];

            [data writeToFile:filePathatomically:YES];

            

            cachedResponse = [[[NSCachedURLResponsealloc]initWithResponse:responsedata:data]autorelease];

            

        }];


        return cachedResponse;

        //NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

        

        

    }

    returnnil;

}



@end


=========

#import "Util.h"

#import <CommonCrypto/CommonDigest.h>


@implementation Util


+ (NSString *)sha1:(NSString *)str {

    constchar *cstr = [strcStringUsingEncoding:NSUTF8StringEncoding];

    NSData *data = [NSDatadataWithBytes:cstrlength:str.length];

    

    uint8_t digest[CC_SHA1_DIGEST_LENGTH];

    

    CC_SHA1(data.bytes, data.length, digest);

    

    NSMutableString* output = [NSMutableStringstringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];

    

    for(int i = 0; i <CC_SHA1_DIGEST_LENGTH; i++) {

        [output appendFormat:@"%02x", digest[i]];

    }

    

    return output;

}


+ (NSString *)md5Hash:(NSString *)str {

    constchar *cStr = [strUTF8String];

    unsignedchar result[16];

    CC_MD5( cStr,strlen(cStr), result );

    NSString *md5Result = [NSStringstringWithFormat:

                           @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",

                           result[0], result[1], result[2], result[3],

                           result[4], result[5], result[6], result[7],

                           result[8], result[9], result[10], result[11],

                           result[12], result[13], result[14], result[15]

                           ];

    return md5Result;

}


@end


=======***********+++++++++++

NSURLProtocol是个抽象类,只要理解为不能直接实例化它,想用它的方法,就去继承它.
NSURLProtocol是NSURLConnection的handle类, 它更像一套协议,如果遵守这套协议,网络请求Request都会经过这套协议里面的方法去处理.
再说简单点,就是对上层的URLRequest请求做拦截,并根据自己的需求场景做定制化响应处理。


图解 : NSURLProtocol 能在系统执行 URLRequest前先去将URLRequest处理了一遍.

// 这个方法是注册NSURLProtocol子类的方法.

+ (BOOL)registerClass:(Class)protocolClass;


// 这个方法是注册后,NSURLProtocol就会通过这个方法确定参数request是否需要被处理

// return : YES 需要经过这个NSURLProtocol"协议"的处理, NO这个协议request不需要遵守这个NSURLProtocol"协议"

// 这个方法的左右 : 1,筛选Request是否需要遵守这个NSURLRequest , 2,处理http: , httpsURL

+ (BOOL)canInitWithRequest:(NSURLRequest *)request;


// 这个方法就是返回request,当然这里可以处理的需求有 : 1,规范化请求头的信息 2, 处理DNS劫持,重定向App中所有的请求指向等

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;


// 这个方法主要用来判断两个请求是否是同一个请求,如果是,则可以使用缓存数据,通常只需要调用父类的实现即可,默认为YES,而且一般不在这里做事情

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b;


// abstract Initializes an NSURLProtocol given request, cached response, and client.

// 开始初始化一个NSURLProtocol抽象对象,包含请求, cachedResponse ,和建立client

- (instancetype)initWithRequest:(NSURLRequest *)request cachedResponse:(nullable NSCachedURLResponse *)cachedResponse client:(nullableid <NSURLProtocolClient>)clientNS_DESIGNATED_INITIALIZER;


// 需要在该方法中发起一个请求,对于NSURLConnection来说,就是创建一个NSURLConnection,对于NSURLSession,就是发起一个NSURLSessionTask

// 另外一点就是这个方法之后,会回调<NSURLProtocolClient>协议中的方法,

<NSURLProtocolClient> 的协议方法, 一般和NSURLConnection的代理方法一起使用

- (void)startLoading


// 这个方法是和start是对应的一般在这个方法中,断开Connection

// 另外一点就是当NSURLProtocolClient的协议方法都回调完毕后,就会开始执行这个方法了

- (void)stopLoading



=========

加载一个webView,当loadRequest:开始发送的时候,就开始执行NSURLProtocol里面的方法.

static NSString *const TravinProtocolHandledKey =@"TravinProtocolHandledKey";

这个方法是注册后,NSURLProtocol就会通过这个方法确定参数request是否需要被处理

// return : YES 需要经过这个NSURLProtocol"协议"的处理, NO这个协议request不需要遵守这个NSURLProtocol"协议"

// 这个方法的左右 : 1,筛选Request是否需要遵守这个NSURLRequest , 2,处理http: , httpsURL

+ (BOOL)canInitWithRequest:(NSURLRequest *)request

{

    //只处理httphttps请求

    NSString *scheme = [[request URL] scheme];

    if ( ([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame || [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame))

    {

        //看看是否已经处理过了,防止无限循环

        if ([NSURLProtocol propertyForKey:TravinProtocolHandledKey inRequest:request]) {

            returnNO;

        }

        

        returnYES;

    }

    returnNO;

}


// 这个方法就是返回request,当然这里可以处理的需求有 :

// 1,规范化请求头的信息 2,处理DNS劫持,重定向App中所有的请求指向等

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {

    return request;

}


// 这个方法主要用来判断两个请求是否是同一个请求,

// 如果是,则可以使用缓存数据,通常只需要调用父类的实现即可,默认为YES,而且一般不在这里做事情

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b

{

    return [super requestIsCacheEquivalent:a toRequest:b];

}


// 开始初始化一个NSURLProtocol抽象对象,包含请求, cachedResponse ,和建立client

- (instancetype)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client

{

    self = [super initWithRequest:request cachedResponse:cachedResponse client:client];

    if (self) {

        

    }

    returnself;

}


// 需要在该方法中发起一个请求,对于NSURLConnection来说,就是创建一个NSURLConnection,对于NSURLSession,就是发起一个NSURLSessionTask

// 另外一点就是这个方法之后,会回调<NSURLProtocolClient>协议中的方法,

- (void)startLoading

{

    NSString *cacheKey = self.request.URL.absoluteString;

    // 1.根据URL作为KEY,利用PRCachedURLResponse创建缓存

    TravinCachedURLResponse *cachedResponse = [[TravinObjectCache sharedCache] objectForKey:cacheKey];//根据请求的URL,获取缓存,

    if (cachedResponse && cachedResponse.response && cachedResponse.data) {// 如果有缓存

        

        NSURLResponse *response = cachedResponse.response;

        NSData *data = cachedResponse.data;

        

        [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];

        [self.client URLProtocol:self didLoadData:data];

        [self.client URLProtocolDidFinishLoading:self];

        return;

    }

    

    NSMutableURLRequest *newRequest = [self.request mutableCopy];

    [newRequest setTimeoutInterval:15]; //设置超时请求

    // 给我们处理过的请求设置一个标识符,防止无限循环,

    [NSURLProtocol setProperty:@YES forKey:TravinProtocolHandledKey inRequest:newRequest];

    // 1.根据URL作为KEY,利用PRCachedURLResponse创建缓存,如果没,则创建一个NSURLConnection,将处理的request与这个connection钩起来,同时实现NSConnectionDataDelegate的回调

    self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];// 创建connection

    

    

    

    

    NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];

    //标示改request已经处理过了,防止无限循环

    [NSURLProtocol setProperty:@YES forKey:TravinProtocolHandledKey inRequest:mutableReqeust];

    self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];

}


// 这个方法是和start是对应的一般在这个方法中,断开Connection

// 另外一点就是当NSURLProtocolClient的协议方法都回调完毕后,就会开始执行这个方法了

- (void)stopLoading

{

    // 断开连接

    [self.connection cancel];

}


如果注册了两个NSURLProtocol,执行顺序是怎样?

Protocols的遍历是反向的,也就是最后注册的Protocol会被优先判断



NSURLProtocol-----由于NSURLRequest每一次对链接的请求,都将触发NSURLProtocol的回调,因此对NSURLProtocol合理应用可以很好的达到离线缓存的目的。

  它是一个抽象类,为载入URL的data的一些特定协议提供基础的结构。要实现它里面的函数就必须继承它,因此小Potti将在后面创建一个MWURLProtocol类继承它,并实现它其中的一系列函数。

    而NSURLProtocol其中有个成员就是NSURLProtocolClient的一个实例。因为NSURLProtocol是由一系列的回调函数构成的(注册函数除外),而要对URL的data进行各种操作时就到了调用NSURLProtocolClient实例的时候了,这就实现了一个钩子,去操作URL data。

   NSURLProtocol有以下一系列的回调方法

- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id )client;

+ (BOOL)canInitWithRequest:(NSURLRequest *)request;

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;

- (void)startLoading;

- (void)stopLoading;

   其中canInitWithRequest是询问是否处理该请求的回调,如果不处理则后面所有函数都不会再调用。startLoading和stopLoading是分别对于loading开始从网页上抓取数据,从网页上抓取完数据的回调。其中startLoading称为我们可以重点利用的函数

NSURLProtocolClient主要有以下方法:

 

- (void)URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;

 

- (void)URLProtocol:(NSURLProtocol *)protocol cachedResponseIsValid:(NSCachedURLResponse *)cachedResponse;

 

- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy;

 

- (void)URLProtocol:(NSURLProtocol *)protocol didLoadData:(NSData *)data;

 

- (void)URLProtocolDidFinishLoading:(NSURLProtocol *)protocol;

 

- (void)URLProtocol:(NSURLProtocol *)protocol didFailWithError:(NSError *)error;

 

- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

 

- (void)URLProtocol:(NSURLProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

 

   其中wasRedirectedToRequest是重定向函数,cachedResponseIsValid是对cached的操作,didReceiveResponse是受到Response时的调用处理函数, didLoadData是load完数据时的调用,


这篇关于iOS之网页缓存html----NSURLCache-----NSURLProtocol的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1017747

相关文章

前端如何通过nginx访问本地端口

《前端如何通过nginx访问本地端口》:本文主要介绍前端如何通过nginx访问本地端口的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、nginx安装1、下载(1)下载地址(2)系统选择(3)版本选择2、安装部署(1)解压(2)配置文件修改(3)启动(4)

HTML中meta标签的常见使用案例(示例详解)

《HTML中meta标签的常见使用案例(示例详解)》HTMLmeta标签用于提供文档元数据,涵盖字符编码、SEO优化、社交媒体集成、移动设备适配、浏览器控制及安全隐私设置,优化页面显示与搜索引擎索引... 目录html中meta标签的常见使用案例一、基础功能二、搜索引擎优化(seo)三、社交媒体集成四、移动

HTML input 标签示例详解

《HTMLinput标签示例详解》input标签主要用于接收用户的输入,随type属性值的不同,变换其具体功能,本文通过实例图文并茂的形式给大家介绍HTMLinput标签,感兴趣的朋友一... 目录通用属性输入框单行文本输入框 text密码输入框 password数字输入框 number电子邮件输入编程框

HTML img标签和超链接标签详细介绍

《HTMLimg标签和超链接标签详细介绍》:本文主要介绍了HTML中img标签的使用,包括src属性(指定图片路径)、相对/绝对路径区别、alt替代文本、title提示、宽高控制及边框设置等,详细内容请阅读本文,希望能对你有所帮助... 目录img 标签src 属性alt 属性title 属性width/h

CSS3打造的现代交互式登录界面详细实现过程

《CSS3打造的现代交互式登录界面详细实现过程》本文介绍CSS3和jQuery在登录界面设计中的应用,涵盖动画、选择器、自定义字体及盒模型技术,提升界面美观与交互性,同时优化性能和可访问性,感兴趣的朋... 目录1. css3用户登录界面设计概述1.1 用户界面设计的重要性1.2 CSS3的新特性与优势1.

HTML5 中的<button>标签用法和特征

《HTML5中的<button>标签用法和特征》在HTML5中,button标签用于定义一个可点击的按钮,它是创建交互式网页的重要元素之一,本文将深入解析HTML5中的button标签,详细介绍其属... 目录引言<button> 标签的基本用法<button> 标签的属性typevaluedisabled

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求