注册自定义protocol handler MyURLProtocol
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [NSURLProtocol registerClass:[MyURLProtocol class]]; return YES; } |
几个重要的NSURLProtocol方法
当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]; } } |