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

相关文章

Qt实现对Word网页的读取功能

《Qt实现对Word网页的读取功能》文章介绍了几种在Qt中实现Word文档(.docx/.doc)读写功能的方法,包括基于QAxObject的COM接口调用、DOCX模板替换及跨平台解决方案,重点讨论... 目录1. 核心实现方式2. 基于QAxObject的COM接口调用(Windows专用)2.1 环境

HTML5的input标签的`type`属性值详解和代码示例

《HTML5的input标签的`type`属性值详解和代码示例》HTML5的`input`标签提供了多种`type`属性值,用于创建不同类型的输入控件,满足用户输入的多样化需求,从文本输入、密码输入、... 目录一、引言二、文本类输入类型2.1 text2.2 password2.3 textarea(严格

SpringBoot返回文件让前端下载的几种方式

《SpringBoot返回文件让前端下载的几种方式》文章介绍了开发中文件下载的两种常见解决方案,并详细描述了通过后端进行下载的原理和步骤,包括一次性读取到内存和分块写入响应输出流两种方法,此外,还提供... 目录01 背景02 一次性读取到内存,通过响应输出流输出到前端02 将文件流通过循环写入到响应输出流

SpringBoot+Vue3整合SSE实现实时消息推送功能

《SpringBoot+Vue3整合SSE实现实时消息推送功能》在日常开发中,我们经常需要实现实时消息推送的功能,这篇文章将基于SpringBoot和Vue3来简单实现一个入门级的例子,下面小编就和大... 目录前言先大概介绍下SSE后端实现(SpringBoot)前端实现(vue3)1. 数据类型定义2.

前端Visual Studio Code安装配置教程之下载、汉化、常用组件及基本操作

《前端VisualStudioCode安装配置教程之下载、汉化、常用组件及基本操作》VisualStudioCode是微软推出的一个强大的代码编辑器,功能强大,操作简单便捷,还有着良好的用户界面,... 目录一、Visual Studio Code下载二、汉化三、常用组件1、Auto Rename Tag2

vite搭建vue3项目的搭建步骤

《vite搭建vue3项目的搭建步骤》本文主要介绍了vite搭建vue3项目的搭建步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1.确保Nodejs环境2.使用vite-cli工具3.进入项目安装依赖1.确保Nodejs环境

Nginx搭建前端本地预览环境的完整步骤教学

《Nginx搭建前端本地预览环境的完整步骤教学》这篇文章主要为大家详细介绍了Nginx搭建前端本地预览环境的完整步骤教学,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录项目目录结构核心配置文件:nginx.conf脚本化操作:nginx.shnpm 脚本集成总结:对前端的意义很多

MyBatis延迟加载与多级缓存全解析

《MyBatis延迟加载与多级缓存全解析》文章介绍MyBatis的延迟加载与多级缓存机制,延迟加载按需加载关联数据提升性能,一级缓存会话级默认开启,二级缓存工厂级支持跨会话共享,增删改操作会清空对应缓... 目录MyBATis延迟加载策略一对多示例一对多示例MyBatis框架的缓存一级缓存二级缓存MyBat

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码

通过React实现页面的无限滚动效果

《通过React实现页面的无限滚动效果》今天我们来聊聊无限滚动这个现代Web开发中不可或缺的技术,无论你是刷微博、逛知乎还是看脚本,无限滚动都已经渗透到我们日常的浏览体验中,那么,如何优雅地实现它呢?... 目录1. 早期的解决方案2. 交叉观察者:IntersectionObserver2.1 Inter