原理
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