NSURLSession
类及其相关类为下载内容提供了接口。这个 API 提供了一系列丰富的代理方法来支持授权,而且让你的 APP 在后台被挂起时也能继续下载。
通过 NSURLSession
的 API,你的 APP可以创建一个或者多个事务,其中的每一个事务都用来协助一组相关的数据来传输任务。比如,如果你在写一个浏览器,你的 APP 可能在每一栏或是每一个窗口都创建了一个事务,可能一个用来进行交互,一个用来后台下载。在每一个事务中,你的 APP 都添加了一些了的任务,其中的每一个任务就代表一个请求或是一个特定的 URL(必要时进行重定向)
给定 URL事务的这些任务共享一个事务配置 session,这个对象定义好了连接行为,比如通往同一个主机的相似连接的最大连接数,不管是通过蜂窝移动网络还是别的方式来允许连接。session 的行为一部分是由创建这个配置对象时你调用的方法来决定:
session 配置对象还包含了对 URL cache 和 cookie 存储对象发起请求并处理相应的引用,具体取决于配置和请求类型。
重大说明!
session 对你的 delegate 始终保持强引用,除非你的 app 退出或者 session已明确失效。如果你没有使 session 失效,你的 app 将会内存溢出,直到它终止。
在 session 中,你创建了可上传数据到服务器的任务,然后通过磁盘上的文件,或是内存中的一个或多个 NSData
对象来获取数据。 NSURLSession
的 API 提供了三种类型的任务:
-
data tasks 通过
NSData
对象来发送和接受数据。 data tasks 用于与服务器进行简短频繁的请求。 - Upload tasks 和 data tasks 类似,但是他们也可以发送数据(一般是通过文件的形式),也支持 app 后台上传。
- Download tasks 通过文件的形式来获取数据,并且支持 app 后台上传和下载。
和大多数网络接口一样,NSURLSession
是高度异步的。它通过两种方式中的其中一种来返回数据给 app,取决于你调用的方法:
- 当传输成功或是发生错误时调用 completion handler block;
- 当收到数据或是传输完成时调用 session 的代理方法。
除了通过代理来传递数据,如果你需要通过当前任务的状态(给出一些状态警示)做一些程序上的决定, NSURLSession
的 API 统一提供了状态和进度的属性,方便查询。
URL sessions 同样支持取消,重启,恢复,挂起任务,而且可以在他们停止的地方恢复挂起、取消、失败了的下载。
URL Session Class 层级结构
NSURLSession
API 由下面的类组成(下面的缩进显示的是子类的关系)
- — 一个 session 对象。
- — 用来初始化 session 的配置对象。
-
— 在 session 中表示任务的基类。
- — 用来获取 NSData 对象的 URL 的任务
- — 用来上传文件,并接收 NSData 对象的 URL 的任务。
- — 以磁盘临时文件的形式获取 URL 的内容的任务。
- — 用来建立 TCP/IP连接的任务。
除此之外,NSURLSession
还提供了4个代理, 订了代理方法,你的 app 可以实现这些代理方法,提供对 session 和 task 更加细化的控制。
- — 可处理 session level 事件的代理
- — 可处理和其他所有 task 类型相通的 task level 的方法的代理
- — 可处理与数据和上传任务相关的 task level 的方法的代理
- — 处理与下载任务相关的 task level 的方法的代理
- — 处理与数据流相关的 task level 的方法的代理
最终,NSURLSession
的 API 使用了很多类,这些类也同样使用了其他的 API,比如 NSURLConnection 和 NSURLDownload。共同使用的类包括:
- — 包含了 URL 的对象
- — 封装与 URL 请求,包括 URL、 请求方法等等相关的元数据。
- — 封装服务器相应的请求,如与 Content 的 MIME 类型和长度相关的元数据。
- — 给 HTTP请求添加特定的附加元数据,比如 response headers。
-
— 用来缓存服务器响应的 body data 封装的一个
NSURLResponse
对象。
身份验证和 TLS 定制
当服务器要求身份验证或在 TLS 协商期间提供凭证时,URL Session 通过调用代理方法,让你可以自定义处理身份验证或证书验证。
调用的代理方法取决于你是在处理 task 相关还是 session范围内的挑战。Table 1 给出了两者之间的区别。
**Table 1 ** Session-level and connection-level challenges
Session-wide challenges | Task-specific challenges |
---|---|
- |
当请求需要客户端授权时,如果你没有实现这些方法,URL Session 会通过下面的方式来尝试授权:
- 如果 URL中含有授权信息的话,通过请求的 URL 中的授权信息。
- 在用户的钥匙串( 在 OS X 中)或是 app 的钥匙串(在 iOS 中)寻找网络密码或是证书。
如果验证不可用,或是服务器拒绝了验证,那这个连接将会在没有授权的情况下继续。对于 HTTP 和 HTTPs 请求来说,连接会通过一个对应的 HTTP 状态码反应尝试失败, 也可能会提供可选择的内容(比如私有网站的公开版本)。对于其他类型的 URL(比如 FTP),将会直接连接失败。
注
erberos 身份验证的处理是公开透明的。这里描述的委托方法不适用于 Kerberos 身份验证。
App 传输安全 (ATS)
使用 URL Session
使用 NSURLSession
类发起一个请求:
- 创建一个 session 配置。若是用作后台的 session,这个配置必须包括一个 唯一标识(unique identifier)。 存储这个标识, 当你的 app 崩溃或是被终止或是被挂起时用它来重连 session。
- 创建一个 session, 指定它的配置对象,或是代理。
- 在每个代表一个资源请求的 session 中创建 task 对象。这些 task 对象应该是
—, , or 的子类,具体用哪个取决于你想要做什么。
每个task 开始时都处于挂起状态。你的 App 调用恢复任务后,它会开始下载其对应的资源。
在你开始一个 task 之后,session 会调用其代理方法,如下:
-
服务器发送一个响应;
- 如果你决定追踪重定向,返回步骤2;
- 如果代理没有实现这个方法,这个重定向将会被重定向的最大数字跟进。
-
如果响应是由多个部分组成的编码,session 会在
didiRecieveReponse
代理被多次调用之后再次调用didRecieveData
代理方法。如果出现这样的情况,回调步骤8(处理didRecieveResponse
回调)
- 如果你不需要用到 session 了,可以通过调用 (用来取消未完成的任务)或是 (在这个对象失效前完成未完成的任务)。 如果你不使这个session失效,它会在你的app终止时自动消失(除非它是一个含有正在进行的任务的后台 session) session 失效后,当所有未完成的任务被取消或是完成时,session会调用 URLSession:didBecomeInvalidWithError: 方法。当代理方法返回时,session 会处置对代理的强引用。
如果你的app 取消了一个正在进行的下载任务, 当出现错误时,NSURLSession 对象会调用代理的 URLSession:task:didCompleteWithError: 方法。
后台处理注意事项
因为重启app(或是等待用户重新唤起时)代价是相当高的,在后台session中有些特性是不可用的。如下:
-
session 必须提供一个传递事件的代理,因为在传输进行中app可能会退出或是重启,完成事件的回调 Block 是不支持的、(为了上传和下载),这些代理在传输过程中表现是相同的;
-
只有 HTTP 和 HTTPS 协议是被支持的。其他内置的网络协议和用户网络协议都不被支持;
-
只有上传和下载是被支持的(没有 data 任务);
-
重定向一直被允许;
-
全系统同时进行的后台传输的数量是被限制的;
-
如果后台任务未能满足指定系统吞吐量限制,可能会被取消。也就是说,如果一个长期运行的任务在一段时间内没有发送或者接受足够的数据,它可能会被取消,以后再被唤起。所以,如果可能的话,让一个传输可被重新唤起是很重要的。
-
译者注:也就是说如果你要传输大量的数据,最好设置这个属性为YES,这样的话系统会延迟传输,直到你手机接通电源或是连上 wifi。下载大数据什么的设置为YES就对了
如果这些限制和你 app 的需求有冲突,你可以在 non-background session 中将远程资源下载到一个文件中。这样,当你的用户让你的 iOS app 进入后台或是退出你的 OS X app 时,可以通过调用 cacelByProducingResumeData: 方法来暂停任何进行中的下载任务。当用户重新让 app 进入前台时恢复下载。如果你的 app 在你获取到任何恢复的数据之前终止了,就不能再恢复下载了。
注
后台 session 是为了优化传输少量很大的资源,在必要时可以进行续传。如果可以,你可能想要调查优化服务器端行为的方法 ,来实现这样的用法,比如:
- 在终结点发起发送或接收 zip 或 tar格式的压缩文件的请求,而不是分开调用多次;
- 在终结点发起发送或接收在服务器和客户端之间的增量差异的请求;
- 在终结点发起一个可返回上传ID的请求,这个ID可用来追踪和恢复传输到服务器的数据;
- 添加一个中间的web 服务器代理请求到规范的web服务器,以方便任何上述优化。
NSCopying 行为
session 和 task 对象都遵从 NSCopying 协议,如下:
- 当你的app 拷贝一个session 或是 task 对象时,你会得到一个同样的对象;
- 当你的app拷贝一个配置对象时,你会得到一个你可以独立地修改的拷贝对象。
线程安全
URL Session API 自身完全是线程安全的。你可以在任何一个线程上下文中随意创建 session 和 task,而且,当你的代理方法调用提供的 完成回调时,它的工作已自动被安排在正确的代理队列中。