# 10.NSURLConnection-和-NSURLSession

> `AFNetworking2.0->3.0` 用`NSURLSession`替换了`NSURLConnection`

## 一: 背景

> iOS早期版本提供了了`NSURLConnection`来执行网络请求. 应用开发人员需要管理链接池,并处理应用后台/中断以及请求的恢复. 从`iOS7`开始,苹果发布了`NSURLSession`用来替代`NSURLConnection`

## 二: NSURLSession 优点

使用`NSURLSession`具有以下优点:

* `NSURLSession`对预防如其中的相关请求而言是一个可配置的容器.
  * 例如:对服务器的所有请求都可以配置成始终包含访问令牌
* 你可以得到后台联网的所有好处.这有助于提高电池寿命/支持UIKit的多任务/使用与过程传输相同的委托模型
* 热和网络任务都可以暂停/停止/重启.此处与`NSURLConnection`不同,此处不需要是`NSOperation`的子类
* 你可以使用`NSURLSession`来配置会话以便在每个会话的基础上使用专用存储(缓存/cookie jar等)
* 当使用`NSURLConnection`时,如果遇到了身份验证问题,问题会在任何一个请求中返回,你无法明确知道那个请求遇到了这个问题.使用`NSURLSession`,委托会处理身份验证
* `NSURLConnection`有一些基于`Block`的异步方法,但委托不能使用它们.当发起一个请求时,要么成功,要么失败,即使它需要身份验证.
* 使用`NSURLSession`你可以混合使用.也就是说,可以使用基于`Block`的异步方法,还可以设置委托以处理身份验证

## 三: NSURLConnection vs NSURLSession

* NSURLConnection
  * 一个`Connection`对象代表一个任务,每个任务绑定一个`configuration`,所有的`configuration`共享一个全局储存器(global storage)
* NSURLSession
  * 一个`Session`绑定一个`configuration`,一个`Session`可以创建多个`Task`,每个`Session`都有一个自己的储存器(private storage)

## 四: NSURLSession API

![](https://raw.githubusercontent.com/RyukieSama/RyukieImage/master/Blog/1862021-6d34f00f640514f4.png)

### NSURLSessionConfiguration

![](https://raw.githubusercontent.com/RyukieSama/RyukieImage/master/Blog/1862021-7b0c50fdae01a65c.png)

* 缓存,cookies,证书存储
* 电池使用,网络服务类型
* 请求的数量
* 资源/请求超时时间
* TLS协议
* HTTP代理,cookies,头部
* 子类话的存储器

> Configuration对象默认是可变类型,它们被使用的时候相当于被copy了一份不可变的,在session中不能对中绑定的Configuration进行修改

* 类型:
  * defaultSessionConfiguration : 系统默认
  * ephemeralSessionConfiguration : 仅内存缓存, 不做磁盘缓存的配置
  * backgroundSessionConfiguration : 这里需要指定一个identifier, identifier用来后台重连session对象. (做后台上传/下载就是这个config)

### NSURLSessionTask

![](https://raw.githubusercontent.com/RyukieSama/RyukieImage/master/Blog/1862021-651fb5b7d18581e4.png)

* task被用来取代connection.一个task代表一个任务(相当于NSURLConnection对象)
* 提供任务的状态和进度属性
* 提供任务的取消/挂起/恢复功能
* 区分data和upload任务
* 提供断点续传的实现
* 分类:
  * NSURLSessionTask : Task的抽象基类
  * NSURLSessionDataTask : 以NSData的形式接收一个URLRequest的内容
  * NSURLSessionUploadTask : 上传NSData或者本地磁盘中的文件, 完成后以NSData的形式接收一个URLRequest的响应
  * NSURLSessionDownloadTask : 下载完成后返回临时文件在本地磁盘的URL路径
  * NSURLSessionStreamTask : 用于建立一个TCP/IP连接

### NSURLSessionDelegate

![](https://raw.githubusercontent.com/RyukieSama/RyukieImage/master/Blog/1862021-322f066750c730fb.png)

* 一个代理对象可以处理所有NSURLSession方法
  * Session/task/dataTask/DownloadTask
* 强引用代理对象直到session无效(与平时代理对象weak引用不同),session就会把全部task都取消/完成
* 代理方法有可能会阻塞加载
  * 记得调用completion handler这个block去让session继续工作, 否则会阻塞起来

## 四: Session分类

* sharedSession: 全局session有局限性
* 自定义session: 自定义session,我们用的一般是这个
* 后台session: 也是一种自定义session,专门用来做后台上传下载任务

> 类型由Configuration来决定

## 五: 后台传输

> 只支持上传下载任务,data任务不支持 只支持HTTPS 根据系统资源,很可能会取消掉后台任务,所以最好还是在前台完成 后台任务最好支持断点续传,分段传输

* 系统创建一个守护进程
* 当你的app正在运行的时候, 正常调用代理方法传输数据给你
* 当你的app退出了(回到桌面/crash), 守护进程会继续他的工作, 直到需要重新认证或者完成所有任务
* re-launch你的app, 然后re-create你的后台session, 然后后台session会re-connect守护进程.
* 守护进程此时就会把数据给你.
* 可以通过不同的identifier创建多个后台session.

## 线程安全

> URLSession 的API全部都是线程安全的. 你可以在任何线程上创建session和tasks, task会自动调度到合适的代理队列中运行 后台传输的代理方法URLSession​Did​Finish​Events​For​Background​URLSession:​可能会在其他线程中被调用. 在该方法中你应该回到主线程然后调用completion handler去触发AppDelegate中的application:​handle​Events​For​Background​URLSession:​completion​Handler:​方法.

## 参考

> <https://www.cnblogs.com/kakaluote123/articles/5426923.html> <https://www.jianshu.com/p/056b1817d25a> <https://www.jianshu.com/p/94d214129d4d> <<高性能iOS应用开发>> GauravVaish
