日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用NSURLProtocol实现离线缓存

發布時間:2024/7/23 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用NSURLProtocol实现离线缓存 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、說明:

NSURLProtocol可以攔截任何網絡請求,包含UIWebView中發出的所有請求。但是在WKWebView中,只能攔截到最初始的請求,內嵌的資源下載攔截不到。比如通過WKWebView加載"http://www.baidu.com",則只能攔截到"http://www.baidu.com",網頁內部的資源加載攔截不到。頁面跳轉屬于最初始請求之內,可以攔截到。


二、創建NSURLProtocol的子類,通過下面的代碼注冊此協議類:

[NSURLProtocol registerClass:[MyURLProtocol class]];


三、下面是此子類的代碼:


#import "MyURLProtocol.h"


#define MyURLProtocolHandled @"MyURLProtocolHandled"


//創建archive數據模型,重寫編碼解碼協議

@interface MyCacheData : NSObject


@property(nonatomic,strong) NSURLRequest *request;

@property(nonatomic,strong) NSURLResponse *response;

@property(nonatomic,strong) NSData *data;


@end


@interface NSURLRequest (MutableCopyWorkaround)


- (id)mutableCopyWorkaround;


@end


@interface MyURLProtocol ()


@property(nonatomic,strong) NSURLConnection *connection;

@property(nonatomic,strong) NSMutableData *httpData;

@property(nonatomic,strong) NSURLResponse *response;


@end


@implementation MyURLProtocol


#pragma mark - 重寫NSURLProtocol子類方法


+ (BOOL)canInitWithRequest:(NSURLRequest *)request

{

? ? //如果此請求是攔截到請求之后,接管請求而發起的新請求,則不處理。

? ? if ([request.URL.scheme isEqualToString:@"http"] &&

? ? ? ? [request valueForHTTPHeaderField:MyURLProtocolHandled] == nil)

? ? {

? ? ? ? return YES;

? ? }

? ? return NO;

}


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

{

? ? return request;

}


+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a

?? ? ? ? ? ? ? ? ? ? ? toRequest:(NSURLRequest *)b

{

? ? return [super requestIsCacheEquivalent:a toRequest:b];

}


- (void)startLoading

{

? ? //如果發現已經存在此請求的緩存數據,則返回緩存數據,否則發起新的請求從服務求加載數據

? ? MyCacheData *cacheData = [NSKeyedUnarchiver unarchiveObjectWithFile:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [self cachePathForRequest:self.request]];

? ? if(cacheData != nil)

? ? {

? ? ? ? NSData *data = cacheData.data;

? ? ? ? NSURLResponse *response = cacheData.response;

? ? ? ? NSURLRequest *redirectRequest = cacheData.request;

?? ? ? ?

? ? ? ? //使用NSURLProtocolClient做請求轉向,直接將請求和數據轉發到之前的請求

? ? ? ? if(redirectRequest != nil)

? ? ? ? {

? ? ? ? ? ? [[self client] URLProtocol:self wasRedirectedToRequest:redirectRequest

? ? ? ? ? ? ? ? ? ? ? redirectResponse:response];

? ? ? ? }

? ? ? ? else

? ? ? ? {

? ? ? ? ? ? [[self client] URLProtocol:self didReceiveResponse:response

? ? ? ? ? ? ? ? ? ? cacheStoragePolicy:NSURLCacheStorageNotAllowed];

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

? ? ? ? ? ? [[self client] URLProtocolDidFinishLoading:self];

? ? ? ? }

? ? }

? ? else

? ? {

//接管此網絡請求,發起一個新的請求,后續會將新請求拿到的數據交給之前的舊請求

? ? ? ? NSMutableURLRequest *connectionRequest = [[self request] mutableCopyWorkaround];

? ? ? ? //增加標記,標示是由我們接管而發出的請求

? ? ? ? [connectionRequest setValue:@"Tag" forHTTPHeaderField:MyURLProtocolHandled];

? ? ? ? self.connection = [NSURLConnection connectionWithRequest:connectionRequest

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? delegate:self];

? ? }

}


- (void)stopLoading

{

? ? [self.connection cancel];

? ? self.connection = nil;

}


#pragma mark - 網絡請求代理


- (NSURLRequest *)connection:(NSURLConnection *)connection

?? ? ? ? ? ? willSendRequest:(NSURLRequest *)request

? ? ? ? ? ? redirectResponse:(NSURLResponse *)response

{

? ? if(response != nil)

? ? {

? ? ? ? NSMutableURLRequest *redirectableRequest = [request mutableCopyWorkaround];

?? ? ? ?

? ? ? ? //緩存數據

? ? ? ? MyCacheData *cacheData = [MyCacheData new];

? ? ? ? [cacheData setData:self.httpData];

? ? ? ? [cacheData setResponse:response];

? ? ? ? [cacheData setRequest:redirectableRequest];

?? ? ? ?

? ? ? ? [NSKeyedArchiver archiveRootObject:cacheData

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? toFile:[self cachePathForRequest:[self request]]];

?? ? ? ?

? ? ? ? //將請求和緩存的響應數據轉向到之前的請求

? ? ? ? [[self client] URLProtocol:self wasRedirectedToRequest:redirectableRequest

? ? ? ? ? ? ? ? ? redirectResponse:response];

? ? ? ? return redirectableRequest ;

? ? }

? ? return request;

}


- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection

{

? ? return YES;

}


- (void)connection:(NSURLConnection *)connection

didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

{

? ? [self.client URLProtocol:self didReceiveAuthenticationChallenge:challenge];

}


- (void)connection:(NSURLConnection *)connection

didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

{

? ? [self.client URLProtocol:self didCancelAuthenticationChallenge:challenge];

}


- (void)connection:(NSURLConnection *)connection

didReceiveResponse:(NSURLResponse *)response

{

? ? //保存響應對象

? ? self.response = response;

? ? [self.client URLProtocol:self didReceiveResponse:response

? ? ? ? ? cacheStoragePolicy:NSURLCacheStorageNotAllowed];

}


- (void)connection:(NSURLConnection *)connection

? ? didReceiveData:(NSData *)data

{

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

?? ?

? ? //保存服務器返回的數據

? ? if(self.httpData == nil) {

? ? ? ? self.httpData = [NSMutableData dataWithData: data];

? ? }

? ? else

? ? {

? ? ? ? [self.httpData appendData:data];

? ? }

}


- (NSCachedURLResponse *)connection:(NSURLConnection *)connection

? ? ? ? ? ? ? ? ? willCacheResponse:(NSCachedURLResponse *)cachedResponse

{

? ? return cachedResponse;

}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection

{

? ? [self.client URLProtocolDidFinishLoading:self];

?? ?

? ? //請求加載完畢之后,將數據緩存

? ? MyCacheData *cacheData = [MyCacheData new];

? ? [cacheData setData:self.httpData];

? ? [cacheData setResponse:self.response];

? ? [NSKeyedArchiver archiveRootObject:cacheData

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? toFile:[self cachePathForRequest:self.request]];

?? ?

? ? self.connection = nil;

? ? self.httpData = nil;

? ? self.response = nil;

}


- (void)connection:(NSURLConnection *)connection

? didFailWithError:(NSError *)error

{

? ? [self.client URLProtocol:self didFailWithError:error];

?? ?

? ? self.connection = nil;

? ? self.httpData = nil;

? ? self.response = nil;

}


#pragma mark - 為請求創建緩存路徑


- (NSString *)cachePathForRequest:(NSURLRequest *)aRequest

{

? ? NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NSUserDomainMask, YES) lastObject];

? ? return [cachesPath stringByAppendingPathComponent:

? ? ? ? ? ? [NSString stringWithFormat:@"%ld", [[[aRequest URL] absoluteString] hash]]];

}


@end


@implementation NSURLRequest (MutableCopyWorkaround)


- (id) mutableCopyWorkaround {

? ? NSMutableURLRequest *mutableURLRequest = [[NSMutableURLRequest alloc]

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? initWithURL:[self URL]

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cachePolicy:[self cachePolicy]

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timeoutInterval:[self timeoutInterval]];

? ? [mutableURLRequest setAllHTTPHeaderFields:[self allHTTPHeaderFields]];

? ? return mutableURLRequest;

}


@end


@implementation MyCacheData


-(id) initWithCoder:(NSCoder *) aDecoder

{

? ? self = [super init];

? ? if(!self) {

? ? ? ? return nil;

? ? }

? ? [self setData:[aDecoder decodeObjectForKey:@"data"]];

? ? [self setRequest:[aDecoder decodeObjectForKey:@"request"]];

? ? [self setResponse:[aDecoder decodeObjectForKey:@"response"]];

?? ?

? ? return self;

}


- (void)encodeWithCoder:(NSCoder *)aCoder

{

? ? [aCoder encodeObject:[self data] forKey:@"data"];

? ? [aCoder encodeObject:[self request] forKey:@"request"];

? ? [aCoder encodeObject:[self response] forKey:@"response"];

}


@end


部分代碼轉自:http://tanlimin201.blog.163.com/blog/static/38171407201383032914736/

總結

以上是生活随笔為你收集整理的使用NSURLProtocol实现离线缓存的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。