大多數App內部都會採用UIWebView加載的,雖然這樣減輕了客戶端的工作量,但是,不可避免會遇到網絡差,服務器不穩定等的情況,在這種情況下,webView的加載效果就很差了,嚴重影響客戶體驗。下面介紹一個NSURLProtocol的緩存的思路
一、原理
主要是通過繼承NSURLProtocol,自定義一個子類,然後可以輕鬆的重新定義蘋果的URL加載系統 (URL Loading System)的行爲。通過攔截,可以實現各種操作 。
二、實現的主要步驟
首先,要在AppDelegate.m的
- (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions
裏面進行註冊
[NSURLProtocol registerClass:[MyConnectionURLProtocol class]];
然後,重寫NSURLProtocol的方法
+ (BOOL)canInitWithRequest:(NSURLRequest *)request;
每個請求都會進入這個方法,返回YES表示接管系統請求,自己進行相關操作,返回NO,表示,默認系統的請求。我們可以在這個方法裏面判斷自己需要做處理的連接,可以根據實現webView緩存,判斷要加載的資源在本地是否存在,如果存在,接管系統請求,加載本地資源
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
/*
防止無限循環,因爲一個請求在被攔截處理過程中,也會發起一個請求,這樣又會走到這裏,如果不進行處理,就會造成無限循環
*/
if ([NSURLProtocol propertyForKey:protocolKey inRequest:request]) {
return NO;
}
NSString * url = request.URL.absoluteString;
// 如果url已http或https,開頭,則進行攔截處理,否則不處理
if ([url hasPrefix:@"http"] || [url hasPrefix:@"https"]) {
//判斷要加載的資源本地是否存在
if ([MyConnectionURLProtocol localResourceIsExistWith:request]) {
return YES;
} else {
return NO;
}
}
return NO;
}
這是相應的判斷。
當上面的操作返回爲YES的時候,纔會繼續下面的操作。
- (void)startLoading重寫該方法,需要在該方法中發起一個請求,對於NSURLConnection來說,就是創建一個NSURLConnection,對於NSURLSession,就是發起一個NSURLSessionTask,在這裏可以進行相關的操作,加載本地資源
NSMutableURLRequest * request = [self.request mutableCopy];
// 表示該請求已經被處理,防止無限循環
[NSURLProtocol setProperty:@(YES) forKey:protocolKey inRequest:request];
NSLog(@"URL %@",request.URL.absoluteString);
NSString *str = request.URL.path;
NSString *Regex = nil;
if ([str.pathExtension isEqualToString:@"js"])
{
Regex = [MyConnectionURLProtocol addLocalFileReturnRex:@"js"];
}else if ([str.pathExtension isEqualToString:@"css"])
{
Regex = [MyConnectionURLProtocol addLocalFileReturnRex:@"css"];
}else if ([str.pathExtension isEqualToString:@"jpg"]||[str.pathExtension isEqualToString:@"png"])
{
Regex = [MyConnectionURLProtocol addLocalFileReturnRex:@"img"];
}
[MyConnectionURLProtocol rexString:str rex:Regex success:^(NSString *matchStr) {
NSArray *fileArr = [matchStr componentsSeparatedByString:@"."];
[self addFiledToClient:matchStr MIMEType:fileArr.lastObject];
} faild:^{
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
}];
重寫- (void)stopLoading該方法,需要停止響應的請求
- (void)stopLoading {
[self.connection cancel];
}
此外,還要重寫canonicalRequestForRequest方法,可以增加或修改請求頭等操作,主要是改變request的操作
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
// 修改了請求的頭部信息
NSMutableURLRequest *mutableReqeust = [request mutableCopy];
mutableReqeust = [self redirectHostInRequset:mutableReqeust];
return mutableReqeust;
}
三、實現NSURLConnectionDataDelegate協議代理方
#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
對於數據更新要求不是很及時的,可以採用以上緩存方案。