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完数据时的调用,


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值