iOS NSURLProtocol的具体使用方法详解

本文介绍了iOS NSURLProtocol的具体使用方法详解,分享给大家,具体如下:

NSURLProtocol定义

这两天在优化项目,无意间看到了NSURLProtocol,学习一下顺便总结下来。

NSURLProtocol也是苹果众多黑魔法中的一种,能够让你去重新定义苹果的URL加载系统 (URL Loading System)的行为,URL Loading System里有许多类用于处理URL请求,比如NSURL,NSURLRequest,NSURLConnection和NSURLSession等,当URL Loading System使用NSURLRequest去获取资源的时候,它会创建一个NSURLProtocol子类的实例,NSURLProtocol看起来像是一个协议,但其实这是一个类,而且必须使用该类的子类,并且需要被注册。

NSURLProtocol使用范围

只要是使用NSURLConnection或者 NSURLSession实现的,你都可以通过NSURLProtocol做一些自定义的操作。

1、自定义请求和响应

2、网络的缓存处理(H5离线包 和 网络图片缓存)

3、重定向网络请求

4、为测试提供数据Mocking功能,在没有网络的情况下使用本地数据返回。

5、过滤掉一些非法请求

6、快速进行测试环境的切换

7、拦截图片加载请求,转为从本地文件加载

8、可以拦截UIWebView,基于系统的NSURLConnection或者NSURLSession进行封装的网络请求。目前WKWebView无法被NSURLProtocol拦截。

9、当有多个自定义NSURLProtocol注册到系统中的话,会按照他们注册的反向顺序依次调用URL加载流程。当其中有一个NSURLProtocol拦截到请求的话,后续的NSURLProtocol就无法拦截到该请求。

NSURLProtocol自定义

#import <Foundation/Foundation.h>

@interface CustomURLProtocol : NSURLProtocol

@end

要实现下面的方法

+ canInitWithRequest:
//抽象方法,子类给出是否能相应该请求。如果响应YES,说明自己的CustomURLProtocol实现该请求。

+ canonicalRequestForRequest:
//抽象方法,重写该方法,可以对请求进行修改,例如添加新的头部信息,修改,修改url等,返回修改后的请求。

+ requestIsCacheEquivalent:toRequest:
//看都是缓存了

- startLoading:
//开始下载,需要在该方法中发起一个请求,对于NSURLConnection来说,就是创建一个NSURLConnection,对于NSURLSession,就是发起一个NSURLSessionTask 。一般下载前需要设置该请求正在进行下载,防止多次下载的情况发生

- stopLoading:
//停止相应请求,清空请求Connection 或 Task

使用自定义NSURLProtocol类

1.在单个的UIViewController中使用

//导入自定义NSURLProtocol类
#import "CustomURLProtocol.h"
//在ViewDidLoad中添加拦截网络请求的代码
//注册网络请求拦截
[NSURLProtocol registerClass:[CustomURLProtocol class]];
//在ViewWillDisappear中添加取消网络拦截的代码
//取消注册网络请求拦截
[NSURLProtocol unregisterClass:[CustomURLProtocol class]];

2.拦截整个App中所有的网络请求

//直接在AppDelegate中的didFinishLaunchingWithOptions注册网络拦截代码
//注册Protocol
[NSURLProtocol registerClass:[CustomURLProtocol class]];
NSURLProtocol使用实例

#define URLProtocolHandledKey @"URLProtocolHandledKey"

+ (BOOL)canInitWithRequest:(NSURLRequest *)request{
 //只处理http和https请求
  NSString *scheme = [[request URL] scheme];
  if ( ([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame ||
   [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame)){
    //看看是否已经处理过了,防止无限循环
    if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
      return NO;
    }
    return YES;
  }
  return NO;
}

+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
   /** 可以在此处添加头等信息 */
  NSMutableURLRequest *mutableReqeust = [request mutableCopy];
  mutableReqeust = [self redirectHostInRequset:mutableReqeust];
  return mutableReqeust;
}

+(NSMutableURLRequest*)redirectHostInRequset:(NSMutableURLRequest*)request{
  if ([request.URL host].length == 0) {
    return request;
  }

  NSString *originUrlString = [request.URL absoluteString];
  NSString *originHostString = [request.URL host];
  NSRange hostRange = [originUrlString rangeOfString:originHostString];
  if (hostRange.location == NSNotFound) {
    return request;
  }
  //定向薄荷喵到主页
  NSString *ip = @"bohemiao.com";

  // 替换域名
  NSString *urlString = [originUrlString stringByReplacingCharactersInRange:hostRange withString:ip];
  NSURL *url = [NSURL URLWithString:urlString];
  request.URL = url;

  return request;
}

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b{
  return [super requestIsCacheEquivalent:a toRequest:b];
}

- (void)startLoading{
  NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
  //标示该request已经处理过了,防止无限循环
  [NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];
  self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];
  //使用NSURLSession也是一样的
}

- (void)stopLoading{
  [self.connection cancel];
}

- (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];
}

上面用到的一些NSURLProtocolClient方法

@protocol NSURLProtocolClient <NSObject>

//请求重定向
- (void)URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;

// 响应缓存是否合法
- (void)URLProtocol:(NSURLProtocol *)protocol cachedResponseIsValid:(NSCachedURLResponse *)cachedResponse;

//刚接收到Response信息
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy;

//数据加载成功
- (void)URLProtocol:(NSURLProtocol *)protocol didLoadData:(NSData *)data;

//数据完成加载
- (void)URLProtocolDidFinishLoading:(NSURLProtocol *)protocol;

//数据加载失败
- (void)URLProtocol:(NSURLProtocol *)protocol didFailWithError:(NSError *)error;

//为指定的请求启动验证
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

//为指定的请求取消验证
- (void)URLProtocol:(NSURLProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

@end

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解iOS开发之NSURLProtocol的那些坑

    NSURLProtocol NSURLProtocol能够让你去重新定义苹果的URL加载系统 (URL Loading System)的行为,URL Loading System里有许多类用于处理URL请求,比如NSURL,NSURLRequest,NSURLConnection和NSURLSession等,当URL Loading System使用NSURLRequest去获取资源的时候,它会创建一个NSURLProtocol子类的实例,你不应该直接实例化一个NSURLProtocol,NSU

  • iOS NSURLProtocol的具体使用方法详解

    本文介绍了iOS NSURLProtocol的具体使用方法详解,分享给大家,具体如下: NSURLProtocol定义 这两天在优化项目,无意间看到了NSURLProtocol,学习一下顺便总结下来. NSURLProtocol也是苹果众多黑魔法中的一种,能够让你去重新定义苹果的URL加载系统 (URL Loading System)的行为,URL Loading System里有许多类用于处理URL请求,比如NSURL,NSURLRequest,NSURLConnection和NSURLSes

  • iOS实现毫秒倒计时的方法详解

    前言 大家应该都知道在app开发中,当展示限时优惠的某些商品时,往往会加一个倒计时,提示用户该商品限时优惠所剩的时间,.那对于开发者来说,这就需要我们去实现的是一个倒计时的功能,这个倒计时根据具体需求,可以以天.小时.分.秒.毫秒作单位. 今天呢,主要说说毫秒计时器.我们知道秒和毫秒之间的进制是1000,也就是说1秒=1000毫秒,那我们做毫秒倒计时器的时候是设置一个时间间隔为1毫秒的计时器,逐一减少毫秒数.但是这样的话太耗时了,所以很多的毫秒计时器中的毫秒数只是0-9之间的数字,这就意味着,这

  • iOS Webview自适应实际内容高度的4种方法详解

    //第一种方法 - (void)webViewDidFinishLoad:(UIWebView *)webView { CGFloat webViewHeight=[webView.scrollView contentSize].height; CGRect newFrame = webView.frame; newFrame.size.height = webViewHeight; webView.frame = newFrame; _webTablewView.contentSize = C

  • IOS 静态方法与动态方法详解

    IOS 静态方法与动态方法详解 1.问题提出 iOS中有静态方法与动态方法,那么两种方法的异同是什么? 2.问题分析 因为每个对象都由相应的数据结构与方法相构成,一个程序可能有多个属于同一个类的对象,而每个对象的数据结构应该是不一的,但方法是相同的,若为每个对象开辟内存空间来存储方法,必然是对内存空间极大的浪费.因此apple是通过类对象与元类来解决这个问题的. 从根本来说,c++.objective-c.java都发源于c语言,因此这些语言实际上可以理解了经过封装的c语言,所以它们更加方便使用

  • IOS点击按钮隐藏状态栏详解及实例代码

    IOS点击按钮隐藏状态栏详解 前言: 最近学习IOS的基础知识,实现隐藏状态栏的功能,这里就记录下来,希望对大家有所帮助 实例代码: @interface SecondViewController () @property (nonatomic, assign,getter=isHideStatus) BOOL hideStatus; @end @implementation SecondViewController - (void)viewDidLoad { [super viewDidLoa

  • IOS UITableView颜色设置的实例详解

    IOS UITableView颜色设置的实例详解 1.系统默认的颜色设置  //无色 cell.selectionStyle = UITableViewCellSelectionStyleNone; //蓝色 cell.selectionStyle = UITableViewCellSelectionStyleBlue; //灰色 cell.selectionStyle = UITableViewCellSelectionStyleGray; 2.自定义颜色和背景设置 改变UITableView

  • IOS 创建并发线程的实例详解

    IOS 创建并发线程的实例详解 创建并发线程 主线程一般都是处理UI界面及用户交互的事儿的.其他的事一般就要另外的线程去处理,如下载,计算等... 现在先简单创建3个线程,分别打印出1-1000,,为了方便,线程3就放在主线程中执行. - (void) firstCounter{ @autoreleasepool { NSUInteger counter = 0; for (counter = 0; counter < 1000; counter++){ NSLog(@"First Cou

  • iOS指纹登录(TouchID)集成方案详解

    TouchID指纹识别是iPhone 5S设备中增加的一项重大功能.苹果的后续移动设备也相继添加了指纹功能,在实际使用中还是相当方便的,比如快捷登录,快捷支付等等.系统提供了相应框架,使用起来还是比较方便的.使用LAContext对象即可完成指纹识别,提高用户体验. 提示:指纹识别必须用真机测试,并且在iOS8以上系统. TouchID API使用 1.添加头文件 #import 2.判断系统版本 //首先判断版本 if (NSFoundationVersionNumber < NSFounda

  • python为QT程序添加图标的方法详解

    Qt是一种基于C++的跨平台图形用户界面应用程序开发框架.如何跨平台?上到服务器上位机,下到嵌入式GUI,上天入地无所不能.Qt最早是由1991年由Qt Company开发,但是到2008年,Qt Company科技被诺基亚公司收购,是的,就是拥有着我们很多情怀的诺基亚.但在2012年,Qt又被Digia收购.等到了2014年,跨平台集成开发环境Qt Creator 3.1.0正式发布出来,至此,全面支持iOS.Android.WP,QT的时代开始逐步展开. 本文重点给大家介绍python为QT

  • IOS之WebSocket框架Starscream案例详解

    传统的网络技术 (也就是 Berkeley sockets) 被认为是可靠和稳定的.但是 Berkeley socket 在某些 web 技术,比如代理和防火墙下不太好使.WebSocket 出现于 2011 年,是一种在客户端和服务端之间建立双向通讯的新技术.WebSocket 比起多个 HTTP 请求来说更有效率并允许长连接. 在 iOS 上使用 WebSocket 并不是那么容易.iOS 和 Mac 库 Starscream 的出现,极大地简化了 WebSocket 的创建和使用. 注:本

随机推荐