# 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ryukiedev.gitbook.io/wiki/ios/za-xiang/nsurlconnection-he-nsurlsession.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
