UIWebView的數據緩存

大多數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];
}

對於數據更新要求不是很及時的,可以採用以上緩存方案。

發佈了59 篇原創文章 · 獲贊 20 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章