对于iOS开发来说,NSURLProtocol想必大多都用到过,从名字上看,感觉实现不了什么大的功能,也像UIButton,UIView等控件来得直观,但是如果你用过它之后,你会觉得NSURLProtocol是iOS中一个非常强大的东西,它能拦截到app的一些网络请求,然后做一些特殊的操作,比如request的配置、request的标记,response的保存、替换等等,让app具有一些不可思议的功能。
我用它主要是用到了NSURLProtocol保存response的功能,具体的需求是保存UIWebView中加载的图片数据,用于一些图片native化的展示功能,刚接到这个需求的时候,是想办法从UIWebView的缓存中下手去找这些下载好的图片资源,但是UIWebView似乎对缓存加过密,而且也无法识别具体哪个资源,所以放弃去从这个方向实现这个功能;面对这种需求,NSURLProtocol的用武之地句来了,它可以拦截所有的图片相关的request,然后在收到response的时候保存一份到磁盘,这样就可以拿到保存的数据了,成功地实现了这个功能。
NSURLProtocol的使用也是很简单了,自定义一个类继承自NSURLProtocol,然后实现以下几个方法就可以实现请求的拦截了
1,+ (BOOL)canInitWithRequest:(NSURLRequest*)request;
用于决定这个请求是否需要处理,返回YES就会继续往下走了
2,+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;
如果第一步返回YES后就可以通过此方法拿到你需要拦截的request,然后进行配置,最后返回给NSProtocol,如果不需要添加参数的直接返回传入的request就好了
3,- (void)stopLoading
停止请求的回调
4,- (void)startLoading
这个方法是告诉你这个request开始加载了,然后可以拿到request,进行自定义的NSURLConnection去下载这个request,最后在这个connection的代理方法中把请求的结果设置到NSProtocol的response中就完成了整个请求拦截的过程了;
在这个过程中可以在connection的代理方法中自己去保存一份这个请求的data,就可以实现图片数据的保存了,在connection的代理方法中会用到下面几个方法:
1,[[self client] URLProtocol:self didLoadData:data];
connection收到数据的时候调用
2,[[self client] URLProtocol:self didFailWithError:error];
connection失败的时候调用
3,[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
connection收到response的时候调用
4,[[self client] URLProtocolDidFinishLoading:self];
connection请求完成的时候调用
完成以上4个方法,就完成了请求结果的对NSProtocol的设置,完成了整个流程,NSURLProtocol用法很强大,也可以缓存整个webView页面的数据,或者替换自己本地的一些数据等
注意事项:
1,canInitWithRequest会多次调用,自己在protocol中自己建立的connetion也会走这个方法,如果也返回YES,就会循环调用;所以在canInitWithRequest判断时候要区分这个自己在protocol中建立的请求,即在startLoading方法中调用forHTTPHeaderField去设置一个特定的Header,在canInitWithRequest中就可以识别出来这个请求,返回NO就行了
2,实用NSProtocol的时候需要调用[NSURLProtocol registerClass:]方法去register这个自定义的protocol类,在不用的时候也要去调用[NSURLProtocol unregisterClass:]这个方法
3,app只会有一个NSURLProtocol类生效,谁后面调用registerClass,就是谁生效
4,WKWebView只能通过私有api去使用NSURLProtocol的,上线appstore有被拒的风险
网友评论