【转】 NSURLProtocol和NSRunLoop的那些坑

转自:http://xiangwangfeng.com/2014/11/29/NSURLProtocol%E5%92%8CNSRunLoop%E7%9A%84%E9%82%A3%E4%BA%9B%E5%9D%91/

参考:http://www.raywenderlich.com/59982/nsurlprotocol-tutorial

 

最近用AFNetworking替换掉了工程里的ASIHttpRequest,结果陆续碰到很多问题:

  • 如何统一地添加全局的HTTP头(不仅仅是UA而已)
  • 如何优雅地进行流量统计
  • 对特定的地址进行CDN加速(URL到IP的替换)
  • 怎么实现HTTP的同步请求

前三个需求对于ASIHttpReqeust来说都不是问题,只需要在几个统一的点进行修改即可。而使用AFNetworking后就没有那么容易了:一方面AFNetworking中生成NSURLRequest的点比较多,并没有一个统一的路径。其次工程中会有部分直接使用NSURLConnecion的场景,无法统一。经cyzju提醒发现了NSURLProtocol这个大杀器,可惜对应的文档过于简略,唯一比较详细的介绍就只有RW的这篇教程而已,掉了很多坑,值得记上一笔。

NSURLProtocol

概念

NSURLProtocol也是苹果众多黑魔法中的一种,使用它可以轻松地重定义整个URL Loading System。当你注册自定义NSURLProtocol后,就有机会对所有的请求进行统一的处理,基于这一点它可以让你

  • 自定义请求和响应
  • 提供自定义的全局缓存支持
  • 重定向网络请求
  • 提供HTTP Mocking (方便前期测试)
  • 其他一些全局的网络请求修改需求

使用方法

继承NSURLPorotocl,并注册你的NSURLProtocol

[NSURLProtocol registerClass:[YXURLProtocol class]];

当NSURLConnection准备发起请求时,它会遍历所有已注册的NSURLProtocol,询问它们能否处理当前请求。所以你需要尽早注册这个Protocol。

实现NSURLProtocol的相关方法

当遍历到我们自定义的NSURLProtocol时,系统先会调用canInitWithRequest:这个方法。顾名思义,这是整个流程的入口,只有这个方法返回YES我们才能够继续后续的处理。我们可以在这个方法的实现里面进行请求的过滤,筛选出需要进行处理的请求。

+ (BOOL)canInitWithRequest:(NSURLRequest *)request { if ([NSURLProtocol propertyForKey:YXURLProtocolHandled inRequest:request]) { return NO; } NSString *scheme = [[request URL] scheme]; NSDictionary *dict = [request allHTTPHeaderFields]; return [dict objectForKey:@"custom_header"] == nil && ([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame || [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame); }

当筛选出需要处理的请求后,就可以进行后续的处理,需要至少实现如下4个方法

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { return request; } + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b { return [super requestIsCacheEquivalent:a toRequest:b]; } - (void)startLoading { NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy]; [YXURLProtocol applyCustomHeaders:mutableReqeust]; [NSURLProtocol setProperty:@(YES) forKey:YXURLProtocolHandled inRequest:mutableReqeust]; self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self]; } - (void)stopLoading { [self.connection cancel]; self.connection = nil; }
  • canonicalRequestForRequest: 返回规范化后的request,一般就只是返回当前request即可。
  • requestIsCacheEquivalent:toRequest: 用于判断你的自定义reqeust是否相同,这里返回默认实现即可。它的主要应用场景是某些直接使用缓存而非再次请求网络的地方。
  • startLoading和stopLoading 实现请求和取消流程。

实现NSURLConnectionDelegate和NSURLConnectionDataDelegate

因为在第二步中我们接管了整个请求过程,所以需要实现相应的协议并使用NSURLProtocolClient将消息回传给URL Loading System。在我们的场景中推荐实现所有协议。

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { [self.client URLProtocol:self didFailWithError:error]; } - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response { if (response != nil) { [[self client] URLProtocol:self wasRedirectedToRequest:request redirectResponse:response]; } return request; } - (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection { return YES; } - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { [self.client URLProtocol:self didReceiveAuthenticationChallenge:challenge]; } - (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { [self.client URLProtocol:self didCancelAuthenticationChallenge:challenge]; } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:[[self request] cachePolicy]]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.client URLProtocol:self didLoadData:data]; } - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { return cachedResponse; } - (void)

转载于:https://www.cnblogs.com/ioslps/p/4269215.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值