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

相关文章

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

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

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

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

CSS Anchor Positioning重新定义锚点定位的时代来临(最新推荐)

《CSSAnchorPositioning重新定义锚点定位的时代来临(最新推荐)》CSSAnchorPositioning是一项仍在草案中的新特性,由Chrome125开始提供原生支持需... 目录 css Anchor Positioning:重新定义「锚定定位」的时代来了! 什么是 Anchor Pos

CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比

《CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比》CSS中的position属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布... css 中的 position 属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布局和层叠关

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

全面解析HTML5中Checkbox标签

《全面解析HTML5中Checkbox标签》Checkbox是HTML5中非常重要的表单元素之一,通过合理使用其属性和样式自定义方法,可以为用户提供丰富多样的交互体验,这篇文章给大家介绍HTML5中C... 在html5中,Checkbox(复选框)是一种常用的表单元素,允许用户在一组选项中选择多个项目。本

HTML5 搜索框Search Box详解

《HTML5搜索框SearchBox详解》HTML5的搜索框是一个强大的工具,能够有效提升用户体验,通过结合自动补全功能和适当的样式,可以创建出既美观又实用的搜索界面,这篇文章给大家介绍HTML5... html5 搜索框(Search Box)详解搜索框是一个用于输入查询内容的控件,通常用于网站或应用程

CSS3中的字体及相关属性详解

《CSS3中的字体及相关属性详解》:本文主要介绍了CSS3中的字体及相关属性,详细内容请阅读本文,希望能对你有所帮助... 字体网页字体的三个来源:用户机器上安装的字体,放心使用。保存在第三方网站上的字体,例如Typekit和Google,可以link标签链接到你的页面上。保存在你自己Web服务器上的字

html 滚动条滚动过快会留下边框线的解决方案

《html滚动条滚动过快会留下边框线的解决方案》:本文主要介绍了html滚动条滚动过快会留下边框线的解决方案,解决方法很简单,详细内容请阅读本文,希望能对你有所帮助... 滚动条滚动过快时,会留下边框线但其实大部分时候是这样的,没有多出边框线的滚动条滚动过快时留下边框线的问题通常与滚动条样式和滚动行

使用vscode搭建pywebview集成vue项目实践

《使用vscode搭建pywebview集成vue项目实践》:本文主要介绍使用vscode搭建pywebview集成vue项目实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录环境准备项目源码下载项目说明调试与生成可执行文件核心代码说明总结本节我们使用pythonpywebv