本文转载至 http://blog.csdn.net/u014011807/article/details/39894247

NSURLProtocol 是iOS中非常重要的一个部分,我们经常会在以下地方用到它:

(1)网络请求代理转发(FQ 网络加速等)

(2)离线缓存策略

总之,只要是需要对本地的URL请求进行截获的,我们都需要使用这个东东。

IOS中我们经常使用的网络请求NSURLConnection以及WebView的页面加载都会被NSURLProtocol截获,因此这个部分的核心就是如何来用这个部分:

下面我将根据使用的步骤来描述NSURLProtocol的使用过程:

最终运行结果:

(1)首先我们需要创建一个类,继承NSURLProtocol

并且实现代理继承:

@interfaceMyURLProtocol () <NSURLConnectionDelegate>

@end

(2)注册这个协议

一般情况下,这个协议在AppDelegate文件中注册:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

[NSURLProtocol  registerClass:[MyURLProtocolclass]];

// Override point for customization after application launch.

returnYES;

}

下面就可以使用这个东东了

(3)下面准备好一段WebView的页面加载代码,这个太简单了,不详细说了,给一个参考代码:

- (void) sendRequest {

NSString *text =self.textField.text;

if (![textisEqualToString:@""]) {

NSURL *url = [NSURLURLWithString:text];

NSURLRequest *request = [NSURLRequestrequestWithURL:url];

[self.webView loadRequest:request];

}

}

(4)可以正常的使用这个NSURLProtocol只需要简单的使用下面9个方法,这九个方法是这个协议可以实现的最基本和最重要的几个方法,当然它还有很多高级的功能,这里就不一一介绍了。

最重要的9个方法如下:

<1>

@method:创建NSURLProtocol实例,NSURLProtocol注册之后,所有的NSURLConnection都会通过这个方法检查是否持有该Http请求。

@parma :

@return: YES:持有该Http请求NO:不持有该Http请求

+ (BOOL)canInitWithRequest:(NSURLRequest *)request

#pragma mark --NSURLProtocol Hold RelevantMethod 4个方法

<2-5>

@method: NSURLProtocol抽象类必须要实现。通常情况下这里有一个最低的标准:即输入输出请求满足最基本的协议规范一致。因此这里简单的做法可以直接返回。一般情况下我们是不会去更改这个请求的。如果你想更改,比如给这个request添加一个title,组合成一个新的http请求。

@parma :本地HttpRequest请求:request

@return:直接转发

+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest *)request

@method: NSURLProtocol缓存系统设置:如果有两个URL请求,并且他们是相等的,那么这里可以使用相同的缓存空间

@parma :本地HttpRequest请求:request

@return:

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest*)b

@method:获取网站上的数据建立connect连接

@parma :

@return:

- (void)startLoading

@method:当前Connection连接取消的时候被调用。尤其要注意这个StopLoading方法,在本地NSURLRequest初始化的时候,有一个超时时间,在低速网络下,有可能页面还没来得及加载完,这个StopLoading方法就被调用了。

@parma :

@return:

- (void)stopLoading

<6-9>接收数据

#pragma mark --NSURLProtocol Delegate 4个方法

-                 (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response

-                 (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data

-                 (void)connectionDidFinishLoading:(NSURLConnection*)connection

-                 (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error

注意这里的方法中:

canInitWithRequest 会创建一个实例,YES时候,然后继续调用startLoading。这里会继续调用canInitWithRequest。陷入死循环,因此这里我们常用的做法是设置一个[NSURLProtocolsetProperty:@YESforKey:@"MyURLProtocolHandledKey"inRequest:newRequest];

这样就可以避免程序陷入死循环。

(5)下面给出一段参考代码:

@implementation MyURLProtocol

/**

@method: 创建NSURLProtocol实例,NSURLProtocol注册之后,所有的NSURLConnection都会通过这个方法检查是否持有该Http请求。

@parma :

@return: YES:持有该Http请求 NO:不持有该Http请求

*/

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {

staticNSUInteger requestCount =0;

NSLog(@"Request #%u: URL = %@", requestCount++, request);

if([NSURLProtocolpropertyForKey:@"MyURLProtocolHandledKey"inRequest:request]) {

returnNO;

}

returnYES;

}

#pragma mark --NSURLProtocol Hold Relevant Method

/**

@method: NSURLProtocol抽象类必须要实现。通常情况下这里有一个最低的标准:即输入输出请求满足最基本的协议规范一致。因此这里简单的做法可以直接返回。一般情况下我们是不会去更改这个请求的。如果你想更改,比如给这个request添加一个title,组合成一个新的http请求。

@parma : 本地HttpRequest请求:request

@return: 直接转发

*/

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest*)request {

return request;

}

/**

@method: NSURLProtocol缓存系统设置:如果有两个URL请求,并且他们是相等的,那么这里可以使用相同的缓存空间

@parma : 本地HttpRequest请求:request

@return:

*/

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {

return [superrequestIsCacheEquivalent:atoRequest:b];

}

- (void)startLoading {

NSMutableURLRequest *newRequest = [self.requestmutableCopy];

[NSURLProtocolsetProperty:@YESforKey:@"MyURLProtocolHandledKey"inRequest:newRequest];

self.connection = [NSURLConnectionconnectionWithRequest:newRequestdelegate:self];

}

/**

@method: 当前Connection连接取消的时候被调用

@parma :

@return:

*/

- (void)stopLoading {

[self.connectioncancel];

self.connection =nil;

}

#pragma mark --NSURLProtocol Delegate

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

[self.clientURLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];

}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

[self.clientURLProtocol:selfdidLoadData:data];

}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

[self.clientURLProtocolDidFinishLoading:self];

}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {

[self.clientURLProtocol:selfdidFailWithError:error];

}

@end

IOS网络篇1之截取本地URL请求(NSURLProtocol)的更多相关文章

  1. iOS网络篇

    iOS网络请求三步: 1.新建URL连接 2.新建请求(请求新建的URL连接) 3.建立连接. 然后就可以获取数据了. 一.同步GET请求方法 -(void)synchronizationGet { ...

  2. ios -网络加载json和本地加载json

    1网络加载json的时候,要在模型的实现文件里写: - (void)setValue:(id)value forKey:(NSString *)key { } 2本地加载json的时候,要在模型的实现 ...

  3. IOS网络第二天 - 01-基本的HTTP请求

    ***************** #import "HMViewController.h" #import "MBProgressHUD+MJ.h" @int ...

  4. IOS网络第一天-01基本的HTTP请求

    *************************** #import "HMViewController.h" #import "MBProgressHUD+MJ.h& ...

  5. iOS网络相关零散知识总结

    iOS网络相关零散知识总结 1. URL和HTTP知识 (1) URL的全称是Uniform Resource Locator(统一资源定位符). URL的基本格式 = 协议://主机地址/路径   ...

  6. iOS开发网络篇—搭建本地服务器

    iOS开发网络篇—搭建本地服务器 一.简单说明 说明:提前下载好相关软件,且安装目录最好安装在全英文路径下.如果路径有中文名,那么可能会出现一些莫名其妙的问题. 提示:提前准备好的软件 apache- ...

  7. iOS开发网络篇—HTTP协议

    iOS开发网络篇—HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...

  8. iOS开发网络篇—文件的上传

    iOS开发网络篇—文件的上传 说明:文件上传使用的时POST请求,通常把要上传的数据保存在请求体中.本文介绍如何不借助第三方框架实现iOS开发中得文件上传. 由于过程较为复杂,因此本文只贴出部分关键代 ...

  9. 02.iOS开发网络篇—HTTP协议

    iOS开发网络篇—HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...

随机推荐

  1. 完全图解RNN、RNN变体、Seq2Seq、Attention机制

    完全图解RNN.RNN变体.Seq2Seq.Attention机制 本文主要是利用图片的形式,详细地介绍了经典的RNN.RNN几个重要变体,以及Seq2Seq模型.Attention机制.希望这篇文章 ...

  2. 高通 双MIC 设置

    android O中设置双MIC降噪,需要在build.prop添加属性"ro.vendor.audio.sdk.fluencetype"属性. 属性值位于hardware/qco ...

  3. 转:ios Sqlite数据库增删改查基本操作

    研究了几天的数据库,终于把它给搞出来了.Sqlite是ios上最常用的数据库之一,大家还是有必要了解一下的.这是仿照网上的一个例子做的,有些部分写的不好,我稍作了修改,以讲解为主,主要让大家能够明白如 ...

  4. Spring JDBC SqlQuery类示例

    org.springframework.jdbc.object.SqlQuery类提供了表示SQL查询的可重用操作对象. 使用到的 Student 表的结构如下 - CREATE TABLE Stud ...

  5. C++编程经验-返回局部变量的讨论(转)

    返回局部变量没问题 如果返回局部变量有问题,函数的意义还有吗? 全局变量还用返回吗?  返回指向局部变量的指针才有问题, 函数退栈之后,局部变量消失, 指针将指向未知区域,所以出现问题.   返回局部 ...

  6. MySQL 数据库定时自动备份

    创建备份目录 cd /home mkdir backup cd backup 创建备份 Shell 脚本: vim DatabaseName.sh #!/bin/bash /usr/local/mys ...

  7. mongo文件空间

    mongo的文件空间,是由一个一个的文件空间组成,如下图 在mongodb刚安装完成时只有一个指定的db都只有一个文件空间而已,例如这里的db是filedb 那么他的第一个文件空间为filedb.0, ...

  8. DTD与模式

    摘要 我们在制作页面时必须要测的就是IE浏览器,毕竟IE浏览器市场占有率还是很高.随着HTML5的流行,可能项目要求兼容IE最低版本为IE8或者更高,但是还是有很多项目兼容IE低版本.所以我们经常会碰 ...

  9. python2和3的区别,怎么样做到轻松切换2和3

    以下是菜鸟教程列举的.这些零散的改变需要注意. 下面这些东西可能平时的程序根本没用到,或者稍加注意就可以了.但2和3最主要的区别是,掌握编码. 编码在所有程序中无处不在,处理不好,要么乱码,要么编码解 ...

  10. python内存泄漏,python垃圾手动回收,1

    部署的舆情系统,内存变大,找原因. 一个小例子. def func(): local_list = list(range(10000000)) func() time.sleep(200) 能够观察到 ...