利用NSURLProtocol实现webView缓存

来源:互联网 发布:vb财务管理系统源码 编辑:程序博客网 时间:2024/06/11 23:10
注册自定义protocol handler MyURLProtocol
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    [NSURLProtocol registerClass:[MyURLProtocol class]];    return YES;}

几个重要的NSURLProtocol方法
+(BOOL)canInitWithRequest:(NSURLRequest*)request;
当URL loading System接收到一个请求时,系统会去寻找一个注册过的protocol handler来处理这个请求。每一个protocol handler通过该方法告诉系统是否可以处理该请求。
return YES ,系统将会依赖该protocol handler 来处理这个请求。
如果所有的自定义protocol handler都返回NO, 系统会用自己的默认行为来处理这个请求。

如果你自定义了一个新的protocol foo:// 你可以在这里判断是否这个URL scheme 是foo。如果是,用自定义protocol handler 返回YES,来处理。

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;
NSURLProtocol的抽象方法,子类必须进行实现。返回规范化后的request,这个方法给了我们重新处理request的机会,比如如果我们需要为request加一个header那么在这里会是一个不错的时机。

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b;
在这里可以指定两个不同的请求,视为同一个请求。它们会使用相同的缓存数据

- (void)startLoading和-(void)stopLoading
开始请求数据和结束请求数据

几个NSURLConnection的代理方法

-(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];}
在这些代理方法中我们拿到请求的进展过程,并通过urlprotocol handler 的client 将进展告诉系统,从而对系统进行代理。

运行程序,发生了什么? 死循环!
解决办法
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {    static NSUInteger requestCount = 0;    NSLog(@"Request #%u: URL = %@", requestCount++, request);     if ([NSURLProtocol propertyForKey:@"MyURLProtocolHandledKey" inRequest:request]) {        return NO;    }     return YES;} - (void)startLoading {    NSMutableURLRequest *newRequest = [self.request mutableCopy];    [NSURLProtocol setProperty:@YES forKey:@"MyURLProtocolHandledKey" inRequest:newRequest];     self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];}

本地缓存网络请求
@property (nonatomic, strong) NSMutableData *mutableData;@property (nonatomic, strong) NSURLResponse *response;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];     self.response = response;    self.mutableData = [[NSMutableData alloc] init];} - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {    [self.client URLProtocol:self didLoadData:data];    [self.mutableData appendData:data];} - (void)connectionDidFinishLoading:(NSURLConnection *)connection {    [self.client URLProtocolDidFinishLoading:self];    [self saveCachedResponse];}




- (void)saveCachedResponse {    NSLog(@"saving cached response");     // 1.    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];    NSManagedObjectContext *context = delegate.managedObjectContext;     // 2.    CachedURLResponse *cachedResponse = [NSEntityDescription insertNewObjectForEntityForName:@"CachedURLResponse"                                                                      inManagedObjectContext:context];    cachedResponse.data = self.mutableData;    cachedResponse.url = self.request.URL.absoluteString;    cachedResponse.timestamp = [NSDate date];    cachedResponse.mimeType = self.response.MIMEType;    cachedResponse.encoding = self.response.textEncodingName;     // 3.    NSError *error;    BOOL const success = [context save:&error];    if (!success) {        NSLog(@"Could not cache the response.");    }}

- (CachedURLResponse *)cachedResponseForCurrentRequest {    // 1.    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];    NSManagedObjectContext *context = delegate.managedObjectContext;     // 2.    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];    NSEntityDescription *entity = [NSEntityDescription entityForName:@"CachedURLResponse"                                              inManagedObjectContext:context];    [fetchRequest setEntity:entity];     // 3.    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"url == %@", self.request.URL.absoluteString];    [fetchRequest setPredicate:predicate];     // 4.    NSError *error;    NSArray *result = [context executeFetchRequest:fetchRequest error:&error];     // 5.    if (result && result.count > 0) {        return result[0];    }     return nil;}


- (void)startLoading {    // 1.    CachedURLResponse *cachedResponse = [self cachedResponseForCurrentRequest];    if (cachedResponse) {        NSLog(@"serving response from cache");         // 2.        NSData *data = cachedResponse.data;        NSString *mimeType = cachedResponse.mimeType;        NSString *encoding = cachedResponse.encoding;         // 3.        NSURLResponse *response = [[NSURLResponse alloc] initWithURL:self.request.URL                                                            MIMEType:mimeType                                               expectedContentLength:data.length                                                    textEncodingName:encoding];         // 4.        [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];        [self.client URLProtocol:self didLoadData:data];        [self.client URLProtocolDidFinishLoading:self];    } else {        // 5.        NSLog(@"serving response from NSURLConnection");         NSMutableURLRequest *newRequest = [self.request mutableCopy];        [NSURLProtocol setProperty:@YES forKey:@"MyURLProtocolHandledKey" inRequest:newRequest];         self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];    }}

0 0