本文是逐行翻译,便于参照原文,如有歧义或者疑问请阅读原文比较。
于 2017.1.25
================================
1.1
CustomHTTPProtocol shows how to use an NSURLProtocol subclass to intercept the HTTP/HTTPS requests made by a high-level subsystem that does not otherwise expose its network connections. In this specific case, it intercepts the requests made by a UIWebView in order to support custom server trust evaluation. You can use this technique to solve various problems, including:
CustomHTTPProtocol为我们展示了怎样利用NSURLProtocol子类来拦截更高层子系统中未暴露的网络请求连接的HTTP/HTTPs请求。在这个特定的小范例中,为了帮助用户服务器验证,CustomHTTPProtocol拦截了UIWebview中的网络请求。你能用这项技术解决如下问题
o implementing custom HTTPS server trust evaluation in a UIWebView (perhaps to access a server with a self-signed certificate), as shown by this specific sample code
在UIWebView中实现自定义HTTPS服务器信任评估(可能访问具有自签名证书的服务器),如此特定示例代码所示
o allowing HTTPS client identity choice in a UIWebView
在UIWebView中允许HTTPS客户端标识选择
o supporting HTTP (RFC 2617) authentication in a UIWebView
在UIWebView中支持HTTP(RFC 2617)认证
o debugging problems with any subsystem that uses NSURL{Session,Connection}, especially in situations where it uses HTTPS, and thus is not amenable(经得起检验的,易控制的) to packet tracing
调试任何使用NSURL {Session,Connection}的子系统,特别是在使用HTTPS的情况下,因此不适合包跟踪
Additionally, the core technique shown by this sample (an NSURLProtocol subclass) can be used to solve other problems including:
此外,此示例(NSURLProtocol子类)展示的核心技术也可用于解决其他问题,包括:
o forcing UIWebView to run through a custom proxy (easy to set up in the NSURLSession used for the recursive requests)
让UIWView运行在自定义的代理中(在NSURLSession中更容易设置递归请求)
o running HTTP requests over some non-standard transport scheme (HTTP over an External Accessory stream pair, for example)
通过某些非标准传输方案(例如通过EAAccessory传输的HTTP请求)运行HTTP请求 注: External Accessory Framework是提供了配件连接iOS设备的通道。开发者可以通过它来开发连接配件的app。
o supporting custom URL schemes for HTTP Live Streaming encryption keys
支持HTTP Live Streaming加密密钥的自定义URL方案
CustomHTTPProtocol requires iOS 7 or later, although the NSURLProtocol subclass technique should work on any version of iOS and, for that matter, on Mac OS X 10.5 and later.
CustomHTTPProtocol需要iOS 7或更高版本,但是NSURLProtocol子类技术应该可以在任何版本的iOS上运行,在Mac OS X 10.5及更高版本上也是如此。
IMPORTANT: Before using the technique shown by this sample, review the "Compatibility Notes" section, below.
重要信息:在使用此示例所示的技术之前,请查看下面的“兼容性说明”部分。
Packing List
The sample includes three top-level items:
该示例包括三个顶级项目:
o Read Me About CustomHTTPProtocol.txt -- This document.
o Read Me关于CustomHTTPProtocol.txt - 本文档。
o CustomHTTPProtocol.xcodeproj -- An Xcode project for the sample.
o CustomHTTPProtocol.xcodeproj - 样本的Xcode项目。
o CustomHTTPProtocol -- A directory containing all the other stuff.
o CustomHTTPProtocol - 包含所有其他内容的目录。
Within the "CustomHTTPProtocol" directory you will find:
在“CustomHTTPProtocol”目录中,您将找到:
o Info.plist, main.m, Main.storyboard, Icons, Default Images -- Standard things you might find in any iOS app.
Info.plist,main.m,Main.storyboard,Icons,Default Images - 您可以在任何iOS应用程序中找到的标准内容。
o AppDelegate.{h,m} -- The application delegate class; this is a normal app delegate with some minor additions to a) enable the NSURLProtocol subclass, b) support logging from that subclass, and c) actually do the custom server trust evaluation (via a delegate callback from the NSURLProtocol subclass).
o AppDelegate。{h,m} - 应用程序委托类; 这是一个普通的应用程序代理,有一些小的g改动 a)启用NSURLProtocol子类,b)支持从该子类的日志记录,和c)做自定义服务器评估(通过从NSURLProtocol子类的委托回调)。
o ThreadInfo.{h,m} -- A helper class used by the app delegate logging code.
o ThreadInfo。{h,m} - 由应用程序委托日志记录代码使用的助手类。
o WebViewController.{h,m} -- The main view controller, which runs a web view and manages the process of downloading anchor certificates.
主视图控制器,它运行Web视图并管理下载锚点证书的过程。
o WebViewControllerHTML -- Some HTML files used by the above.
o WebViewControllerHTML - 上面代码需要使用的一些HTML文件。
o CredentialsManager.{h,m} -- A singleton model object that maintains the list of trusted anchors for the app.
o CredentialsManager。{h,m} - 一个单例模型对象,维护应用程序的可信锚的列表。
o Core Code -- The code that actually implements the NSURLProtocol subclass. Within this directory you'll find four modules:
o核心代码 - 实际实现NSURLProtocol子类的代码。在此目录中,您将找到四个模块:
CustomHTTPProtocol.{h,m} -- The actual NSURLProtocol subclass.
CustomHTTPProtocol。{h,m} - 实际的NSURLProtocol子类。QNSURLSessionDemux.{h,m} -- A helper class used by instances of the CustomHTTPProtocol class to demultiplex NSURLSession delegate events.
QNSURLSessionDemux。{h,m} - 由CustomHTTPProtocol类的实例用于解构NSURLSession委托事件的辅助类。CanonicalRequest.{h,m} -- A module that contains a single function, CanonicalRequestForRequest, which implements some standard functionality. See the "Caveats" section (below) for more information about this.
CanonicalRequest。{h,m} - 包含单个函数CanonicalRequestForRequest的模块,它实现了一些标准功能。有关详细信息,请参阅“注意事项”部分(如下)。CacheStoragePolicy.{h,m} -- A module that contains a single function, CacheStoragePolicyForRequestAndResponse, which implements some standard functionality. See the "Compatibility Notes" section (below) for more information about this.
CacheStoragePolicy。{h,m} - 包含单个函数CacheStoragePolicyForRequestAndResponse的模块,它实现了一些标准功能。有关详细信息,请参阅“兼容性注释”部分(如下)。
Using the Sample使用范例代码
To use the sample, simply run it on a device or the simulator. It will put up a web view that allows you to pick a number of sites to visit. To run a basic test, do the following:
要使用示例,只需在设备或模拟器上运行它。它会展示一个网络视图,允许你选择一些网站进行访问。要运行基本测试,请执行以下操作:
\1. tap on the "CAcert (HTTPS)" link; you will see an error because the system does not trust the CAcert anchor by default
1.点击“CAcert(HTTPS)”链接; 您将看到错误,因为系统默认不信任CAcert锚点
\2. tap the Sites button to get you back to the top
2.点击网站按钮,回到顶部
\3. tap the "Install CAcert Anchor" link, which takes you to the CAcert anchor install page
3.点击“安装CAcert锚点”链接,将链接转到CAcert锚点安装页面
\4. tap the Install button; wait for the CAcert anchor to install
4.点击安装按钮; 等待CAcert锚点安装
Note: This affects only the CustomHTTPProtocol app, not the system as a whole.
注意:这仅影响CustomHTTPProtocol应用程序,而不影响整个系统。
\5. tap the Sites button to take you back to the top again
5.点击“站点”按钮,将您带回到顶端
\6. tap the "CAcert (HTTPS)" link; this time the site will be displayed because the UIWebView in this app now trusts the CAcert anchor
6.点击“CAcert(HTTPS)”链接; 此时将显示网站,因为此应用程序中的UIWebView现在信任CAcert锚点
IMPORTANT: The app does not remember your installed anchors from launch to launch. See the "Caveats" section (below) for an explanation.
重要信息:该应用程序不记得您从安装启动到安装的锚点。有关说明,请参阅“注意事项”部分(如下)。
Building the Sample构建范例代码
The sample was built using Xcode 5.1.1 on OS X 10.9.4 using the iOS 7.1 SDK. You should be able to just open the project and choose Run from the Product menu.
该示例是使用Xcode 5.1.1在OS X 10.9.4使用iOS 7.1 SDK构建的。您应该只能打开项目并从产品菜单中选择运行
Compatibility Notes兼容性说明
This sample assumes that UIWebView uses NSURLConnection in a way that allows the NSURLProtocol subclass to affect its usage. This is currently true, but there's no guarantee that it will be true forever. Certainly, there are existing subsystems within iOS where this is not the case (for example, the movie playback subsystem).
此示例假设UIWebView使用NSURLConnection以允许NSURLProtocol子类能够在UIWebView上生效。现在这是真实有效的,但不能保证它将永远是真实有效的。当然,在iOS中存在不是这种情况的子系统(例如,电影回放子系统)。
WARNING: If you use an NSURLProtocol subclass to customize UIWebView's behaviour, you should file a bug that describes your requirements and requests that appropriate customization points be provided via the UIWebView delegate.
警告:如果使用NSURLProtocol子类来定制UIWebView的行为,您应该提交一个描述您的需求的错误,并请求通过UIWebView代理提供适当的自定义点。
https://developer.apple.com/bugreporter/
Likewise, if you use this technique for other subsystems within iOS, you should file a bug requesting that those subsystems be enhanced to support the customization points that you require.
同样,如果您对iOS中的其他子系统使用此技术,您应该提交一个错误,要求改造这些子系统以支持您需要的自定义点
If you plan to use a custom NSURLProtocol subclass for movie playback, watch WWDC 2011 Session 408 "HTTP Live Streaming Update" for important information about how NSURLProtocol subclasses interact with the media subsystem.
如果计划使用自定义NSURLProtocol子类进行电影播放,请观看WWDC 2011会话408“HTTP实时流更新”,了解有关NSURLProtocol子类与媒体子系统如何交互的重要信息。
https://developer.apple.com/videos/wwdc/2011/
Be aware that, if a subsystem uses NSURLSession, your custom NSURLProtocol subclass will only see requests issued in the shared session (+[NSURLSession sharedSession]). For the protocol to work in other sessions, it must be listed (via the NSURLSessionConfiguration.protocolClasses property) in the configuration used to create the session.
请注意,如果子系统使用NSURLSession,您的自定义NSURLProtocol子类将只看到在共享会话(+ [NSURLSession sharedSession])中发出的请求。要使协议在其他会话中工作,必须在用于创建会话的配置中列出(通过NSURLSessionConfiguration.protocolClasses属性)。
An NSURLProtocol subclass can potentially affect any piece of code in your process that uses NSURL{Session,Connection} and, as such, represents a real compatibility risk. To minimize the potential for problems:
NSURLProtocol子类可能会影响进程中使用NSURL {Session,Connection}的任何代码段,因此代表了真正的兼容性风险。为了尽量减少潜在的问题:
o limit your scope -- The easiest way to prevent problems is to limit the type of URLs that you handle. To do this, implement +canInitWithRequest: so that it declines to process everything except the specific requests you're interested in. For example, while +canInitWithRequest: in this sample accepts both HTTP and HTTPS requests, it would be sufficient to have it accept only HTTPS requests, allowing HTTP requests to be processed by the default protocol implementation.
o限制您的范围 - 防止问题的最简单方法是限制您处理的URL类型。为了做到这一点,实现+ canInitWithRequest:以便它拒绝处理除了你感兴趣的特定请求之外的任何东西。例如,while + canInitWithRequest:在这个示例接受HTTP和HTTPS请求,它就足以让它接受只有HTTPS请求,允许HTTP请求由默认协议实现处理。
o memory -- Be careful not to use too much memory, particularly on iOS.
o内存 - 小心不要使用太多内存,特别是在iOS上。
o threading -- Be sure to follow the threading rules described below.
o线程 - 请务必遵循下面描述的线程规则。
It's not possible to accurately implement an HTTP/HTTPS NSURLProtocol subclass without reimplementing some system functionality. Any time you reimplement system functionality you run the risk that the system functionality might change, leaving your reimplemention behind. There are two major areas of concern here:
不可能在不重新实现某些系统功能的情况下准确实现HTTP / HTTPS NSURLProtocol子类。每当您重新实现系统功能时,您都会遇到系统功能可能会改变的风险,因此您可以重新实现系统功能。这里有两个主要关注的领域:
o URL canonicalization -- The code in the CanonicalRequestForRequest function is complex, and there's certainly some scope for future compatibility problems.
o URL规范化 - CanonicalRequestForRequest函数中的代码很复杂,并且对于未来的兼容性问题肯定有一定范围。
o cache storage policy -- The code in the CacheStoragePolicyForRequestAndResponse function isn't nearly as complex as the URL canonicalization code, but it is another example of reimplementing system functionality.
o缓存存储策略 - CacheStoragePolicyForRequestAndResponse函数中的代码不像URL规范化代码那么复杂,但它是重新实现系统功能的另一个示例
Threading Notes线程注释
NSURLProtocol subclasses are tricky to implement correctly. The most important issues relate to threading. The methods that an NSURLProtocol subclass is expected to implement can be split into two groups:
NSURLProtocol子类很难正确实现。最重要的问题与线程有关。NSURLProtocol子类期望实现的方法可以分为两组:
o any thread -- These methods may be called from any thread and must be completely thread safe:
o任何线程 - 这些方法可以从任何线程调用,并且必须完全线程安全:
-initWithRequest:cachedResponse:client:
-dealloc
+canInitWithRequest:
+canonicalRequestForRequest:
+requestIsCacheEquivalent:toRequest:
o client thread -- These methods are always called by the client thread:
o客户端线程 - 这些方法总是由客户端线程调用:
-startLoading
-stopLoading
The exact identity of the client thread is unspecified, but you can be assured that:
客户端线程的确切标识未指定,但您可以放心:
o -startLoading is called by the client thread
o -startLoading由客户端线程调用
o -stopLoading will be called by that same client thread
o -stopLoading将由相同的客户端线程调用
o -stopLoading will be called before -dealloc is called
o -stopLoading将在调用-dealloc之前调用
o the client thread will run its run loop
o客户端线程将运行其运行循环
In addition, an NSURLProtocol subclass is expected to call the various methods of the NSURLProtocolClient protocol from the client thread, including all of the following:
此外,NSURLProtocol子类期望从客户端线程调用NSURLProtocolClient协议的各种方法,包括以下所有方法:
-URLProtocol:wasRedirectedToRequest:redirectResponse:
-URLProtocol:didReceiveResponse:cacheStoragePolicy:
-URLProtocol:didLoadData:
-URLProtocolDidFinishLoading:
-URLProtocol:didFailWithError:
-URLProtocol:didReceiveAuthenticationChallenge:
-URLProtocol:didCancelAuthenticationChallenge:
The NSURLProtocol subclass must call the client callbacks in the expected order. This breaks down into three phases:
NSURLProtocol子类必须以预期的顺序调用客户端回调。这分为三个阶段:
\1. pre-response -- In the initial phase the NSURLProtocol can make any number of -URLProtocol:wasRedirectedToRequest:redirectResponse: and -URLProtocol:didReceiveAuthenticationChallenge: callbacks.
1.预响应 - 在初始化阶段,NSURLProtocol可以创建任意数量的-URLProtocol:wasRedirectedToRequest:redirectResponse:和-URLProtocol:didReceiveAuthenticationChallenge:callbacks。
\2. response -- It must then call -URLProtocol:didReceiveResponse:cacheStoragePolicy: to indicate the arrival of a definitive response.
\2. 响应 - 然后它必须调用-URLProtocol:didReceiveResponse:cacheStoragePolicy:来指示确定响应的到达。
\3. post-response -- After receiving a response it may then make any number of -URLProtocol:didLoadData: callbacks, followed by a -URLProtocolDidFinishLoading: callback.
\3. 收到响应后 - 在接收到响应之后,它可以使用任意数量的-URLProtocol:didLoadData:callbacks,随后是一个-URLProtocolDidFinishLoading:回调。
The -URLProtocol:didFailWithError: callback can be made at any time (although keep in mind the following point).
-URLProtocol:didFailWithError:可以随时进行回调(但请记住以下几点)。
The NSURLProtocol subclass must only send one authentication challenge to the client at a time. After calling -URLProtocol:didReceiveAuthenticationChallenge:, it must wait for the client to resolve the challenge before calling any callbacks other than -URLProtocol:didCancelAuthenticationChallenge:. This means that, if the connection fails while there is an outstanding authentication challenge, the NSURLProtocol subclass must call -URLProtocol:didCancelAuthenticationChallenge: before calling -URLProtocol:didFailWithError:.
NSURLProtocol子类只能一次向客户端发送一个身份验证质询。调用-URLProtocol:didReceiveAuthenticationChallenge:后,它必须等待客户端解决挑战,然后再调用任何回调之外的-URLProtocol:didCancelAuthenticationChallenge:。这意味着,如果连接失败,而有一个未完成的身份验证质询,NSURLProtocol子类必须调用-URLProtocol:didCancelAuthenticationChallenge:之前调用-URLProtocol:didFailWithError :.
WARNING: An NSURLProtocol subclass must operate asynchronously. It is not safe for it to block the client thread for extended periods of time. For example, while it's reasonable for an NSURLProtocol subclass to defer work (like an authentication challenge) to the main thread, it must do so asynchronously. If the NSURLProtocol subclass passes a task to the main thread and then blocks waiting for the result, it's likely to deadlock the application.
警告:NSURLProtocol子类必须异步操作。它不能安全地阻止客户端线程很长一段时间。例如,虽然NSURLProtocol子类推迟到主线程的工作(如身份验证质询)是合理的,但它必须异步执行。如果NSURLProtocol子类将任务传递给主线程,然后阻塞等待结果,它可能会死锁应用程序。
Caveats 附加说明
The sample app does not remember your installed anchors from launch to launch. This would be easy to implement by extending the CredentialsManager class to store the anchors, but I chose not to do this in order to keep things simple.
示例应用程序不会记住从启动到启动安装的锚点。这将很容易实现通过扩展CredentialsManager类来存储锚点,但我选择不这样做,以保持简单。
The NSURLProtocolClient protocol has not been extended to support advanced protection spaces rdar://problem/9226151. This means there's no way for your NSURLProtocol subclass to call the NSURLConnection delegate's -connection:canAuthenticateAgainstProtectionSpace: method. If you do send authentication challenges to your client, you must only send standard authentication challenges (that is, challenges whose protection space's authentication method is NSURLAuthenticationMethodDefault, NSURLAuthenticationMethodHTTPBasic, or NSURLAuthenticationMethodHTTPDigest). You must process other authentication challenges yourself (which is often the reason why you implemented the custom NSURLProtocol subclass in the first place).
NSURLProtocolClient协议尚未扩展,以支持高级保护空间<rdar:// problem / 9226151>。这意味着您的NSURLProtocol子类无法调用NSURLConnection委托的-connection:canAuthenticateAgainstProtectionSpace:方法。如果您向客户端发送身份验证挑战,则您必须只发送标准身份验证挑战(即,保护空间的身份验证方法为NSURLAuthenticationMethodDefault,NSURLAuthenticationMethodHTTPBasic或NSURLAuthenticationMethodHTTPDigest的挑战)。您必须自己处理其他身份验证挑战(这通常是您首先实现自定义NSURLProtocol子类的原因)。
Similarly, there is no way for your NSURLProtocol subclass to call the NSURLConnection delegate's -connection:needNewBodyStream: or -connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite: methods (rdar://problem/9226155 and rdar://problem/9226157). The latter is not a serious concern--it just means that your clients don't get upload progress--but the former is a real issue. If you're in a situation where you might need a second copy of a request body, you will need your own logic to make that copy, including the case where the body is a stream.
同样,你的NSURLProtocol子类没有办法调用NSURLConnection委托的-connection:needNewBodyStream:或-connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:methods(<rdar:// problem / 9226155>和<rdar:// problem / 9226157 >)。后者不是一个严重的问题 - 这只是意味着你的客户端不会获得上传进度 - 但前者是一个真正的问题。如果您遇到需要请求正文的第二个副本的情况,您需要使用自己的逻辑来进行该副本,包括正文是流的情况。
And finally, there is no way for your NSURLProtocol subclass to call the NSURLConnection delegate's -connectionShouldUseCredentialStorage: or -connection:willCacheResponse: methods (rdar://problem/9226160). This shouldn't be a problem in most circumstances, but could cause problems for complex clients.
最后,你的NSURLProtocol子类没有办法调用NSURLConnection委托的-connectionShouldUseCredentialStorage:或-connection:willCacheResponse:methods(<rdar:// problem / 9226160>)。这在大多数情况下不应该是问题,但可能对复杂的客户端造成问题。
Creating an NSHTTPURLResponse from scratch is tricky. This sample gets around the issue by calling NSURLConnection recursively, which causes the system to create the NSHTTPURLResponse on its behalf. If you need to do something different, see the "Creating an NSHTTPURLResponse" section below.
从头开始创建NSHTTPURLResponse是棘手的。此示例通过递归调用NSURLConnection来解决问题,这导致系统代表它创建NSHTTPURLResponse。如果您需要执行不同的操作,请参阅下面的“创建NSHTTPURLResponse”部分。
Using a custom NSURLProtocol subclass can cause CFNetwork to leak on HTTP redirects rdar://problem/10093777. To reduce the impact of this leak, minimize the size of your NSURLProtocol subclass object and have it clean up its resources in -stopLoading rather than in -dealloc.
使用自定义NSURLProtocol子类可能导致CFNetwork在HTTP重定向<rdar:// problem / 10093777>上泄漏。为了减少此泄漏的影响,最小化NSURLProtocol子类对象的大小,并在-stopLoading中而不是在-dealloc中清除其资源。
The CanonicalRequest code would most definitely benefit from adopting the NSURLComponents class that was added in iOS 7 and OS X 10.9. The technique it currently uses is less than ideal rdar://problem/17383757.
CanonicalRequest代码最有利于采用在iOS 7和OS X 10.9中添加的NSURLComponents类。它当前使用的技术不太理想<rdar:// problem / 17383757>。
Creating an NSHTTPURLResponse 创建NSHTTPURLResponse
Prior to iOS 5 (and OS X 10.7) there was no supported way to construct a valid NSHTTPURLResponse from scratch rdar://problem/5817126. The sticking point was that the only public initialisation method (-initWithURL:MIMEType:expectedContentLength:textEncodingName:) did not let you specify the HTTP status code or headers. Moreover, because of the interactions between NSURLConnection and CFNetwork, you can't work around this limitation by subclassing NSHTTPURLResponse and overriding the -statusCode and -allHeaderFields methods; such overrides are not seen by all subsystems that use NSURLConnection (most notably UIWebView).
在iOS 5(和OS X 10.7)之前,没有支持的方法从头构建有效的NSHTTPURLResponse <rdar:// problem / 5817126>。关键点是,唯一的公共初始化方法(-initWithURL:MIMEType:expectedContentLength:textEncodingName :)不允许您指定HTTP状态代码或标头。此外,由于NSURLConnection和CFNetwork之间的交互,您不能通过子类化NSHTTPURLResponse并覆盖-statusCode和-allHeaderFields方法来解决此限制; 这样的覆盖不是所有使用NSURLConnection(最引人注目的UIWebView)的子系统。
If you only support iOS 5 or later, this isn't an issue: when you need to construct an NSHTTPURLResponse, simply use the newly introduced -initWithURL:statusCode:HTTPVersion:headerFields: initialisation method. However, if you must support older systems, things get more complex. There are a variety of less-than-ideal workarounds:
如果你只支持iOS 5或更高版本,这不是一个问题:当你需要构造一个NSHTTPURLResponse,只需使用新引入的-initWithURL:statusCode:HTTPVersion:headerFields:initialisation方法。但是,如果您必须支持旧系统,则事情变得更复杂。有多种不太理想的解决方法:
o Actually pass the request off to the default HTTP or HTTPS implementation by calling NSURL{Session,Connection} recursively. This will give you back an NSHTTPURLResponse that you can pass up to your client.
o实际上通过递归调用NSURL {Session,Connection}将请求传递给默认的HTTP或HTTPS实现。这将给你一个NSHTTPURLResponse,你可以传递给你的客户端。
This is the approach shown by this sample.
这是此示例显示的方法。
o An extension of this approach is to implement a small loopback web server that returns the HTTP response you need to generate the correct NSHTTPURLResponse.
o这种方法的扩展是实现一个小的环回Web服务器,它返回生成正确的NSHTTPURLResponse所需的HTTP响应。
o NSHTTPURLResponse supports the NSCoding protocol. If your NSURLProtocol only needs to return a small number of fixed responses, you could create those responses via NSURL{Session,Connection} at build time, archive them, and then unarchive them at run time.
o NSHTTPURLResponse支持NSCoding协议。如果您的NSURLProtocol只需要返回少量的固定响应,您可以在构建时通过NSURL {Session,Connection}创建这些响应,将它们存档,然后在运行时取消存档。
Credits and Version History
If you find any problems with this sample, please file a bug against it.
https://developer.apple.com/bugreporter/
1.0d1..8 (2011..2013) shipped to a limited number of developers on a one-to-one basis.
1.0 (Aug 2013) was the first shipping version.
1.1 (Jul 2014) is an update that changes the protocol to use NSURLSession for its recursive requests. This works around a deadlock issue rdar://problem/17342579 and makes the code more future proof. There were also numerous other minor changes.
Share and Enjoy
Apple Developer Technical Support
Core OS/Hardware
28 Jul 2014