代码改变世界

[转]用NSURLPROTOCOL实现代理和缓存

2013-05-06 10:42  waddell  阅读(2866)  评论(0编辑  收藏  举报

原理

NSURLProtocol可以用来劫持全局的由NSURLConnection发起的网络请求,通过覆写方法,你可以获知NSURLConnection需要发起的NSURLRequest,你可以自行发起网络请求,并且把数据丢过请求的发起者。通过这种方法,一般来说,你可以实现代理和缓存等功能。 由于UIWebView也是走的这套协议,所以你甚至可以自己开发一个走代理的浏览器。

方法

注册自定义协议

[NSURLProtocol registerClass:[HSUProxyURLProtocol class]];

  

实现自定义协议

Header文件

#import <Foundation/Foundation.h>

@interface HSUProxyURLProtocol : NSURLProtocol

@end

  

Implementation文件

#import "HSUProxyURLProtocol.h"

@implementation HSUProxyURLProtocol
{
  #可以在此定义数据容器,连接等
}

- (void)startLoading
{
  #可以这样子拿到原来的请求,用以拼装自己的请求
    NSMutableURLRequest *proxyRequest = [self.request mutableCopy];
}

- (void)stopLoading
{
  #请求在这里该结束了,在此终止自己的请求吧
    [connection cancel];
}

#这几个不是Protocol的方法,是自发起的URLConnection的回调
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
  #此方法会收到一部分或者全部的数据,可以这样子丢给原始请求的发起者
    [self.client URLProtocol:self didLoadData:sourceData];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
  #和上一个方法类似,这里作为错误通知
    [self.client URLProtocol:self didFailWithError:error];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
  #这里是收到响应的头部信息,比如HTTP Header,可视情况做对self.client做相应操作,也可以不做处理
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
  #自己的请求加载完成了,这样子可以通知self.client
    [self.client URLProtocolDidFinishLoading:self];
}

+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
  #根据request来决定要不要劫持
  #需要特别注意的是,如果你用NSURLConnection来发起代理请求,那么那个代理请求的request也同样会经过这里来做判决,所以一定要判断是不是代理请求,然后返回NO
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
  #这里是干嘛的,我还没研究清楚,就简单的返回了原始值,有兴趣的话你可以研究一下
    return request;
}

@end

以上我已经基本描述了每个方法是做什么的,怎么用的。 最后可以参考一下我在开源项目中的实现 Tweet4China2 另参见一个别人写的缓存 RNCachingURLProtocol