长期以来咱们在处理 iOS 中的网络通讯的时候都是直接使用 OC 版 AFNetworking 或者 Swift 版 Alamofire ,可是咱们居然不多会去认真关注 iOS 中的网络基础底层内容。这同时折射出了 iOS 开发中的一个问题:iOS 开发有着丰富的组件、完善的生态、成熟的机制,这些特质让 iOS 开发的门槛低的几乎只要一台 MBP,但这也让开发人员思惟退化慢慢的变成了一名搬砖工。这篇文章将介绍 iOS 底层网络通讯的基础内容。程序员
从服务器获取数据、更新我的资料、下载或者上传文件,这些App中功能都是经过 HTTP 请求进行实现的。为了方便开发者对 HTTP 进行处理,Apple为 咱们提供了 URLSession 组件。URLSession 是 iOS7 以后引入的底层网络通讯架构,在此以前使用的是 NSURLConnection(iOS9 中已废弃)。其实 URLSession 除了指代同名类以外,更大程度上应该表达为整套的网络架构相关的类。URLSession 包含了 NSURLConnection 时代就有的 URLRequest 与 URLCache,可是它将 NSURLConnection 进行了分解。分解后的结构以下图:编程
URLSessionDelegate 只负责处理 Session 级别的事务,诸如服务器信任,客户端证书的评估。该 delegate 并非必须的,若是开发者没有本身设置 delegate 系统会完成默认设置可是必须提供一个 completionHandler 来进行数据处理。缓存
另外一个须要注意的是:不一样于咱们经常使用的编程规范,session 对 delegate 保持这强引用而不是 weak。这代表此处的代码设计会涉及到内存泄漏的问题,因此咱们要当心处理。处理办法是使用单例模式或者经过 finishTasksAndInvalidate() 、 invalidateAndCancel() 方法来使 session 失效,调用后者会马上生效,而前者则会等待 session 明确完成或者失败后才会失效。至于这两个方法的调用时机,你能够在 URLSessionDelegate 或者 URLSessionDataDelegate 及其子类的某个方法中,也能够在控制器的 viewWillDisappear 中调用。不过我建议使用后一种处理方式,由于一个控制器可能存在多个请求任务,若是每一个 Task 都销毁 Session 也就代表同一个 Session 在每一个 Task 开始的时候都须要初始化,这不只致使代码冗余也下降了代码效率。安全
URLSessionConfiguration 对象用于对 URLSession 对象进行初始化配置。这也是 URLSession 与 NSURLConnection 相比最明显的改进之一,咱们能够配置每一个 session 的缓存,协议,cookie,以及证书策略(credential policy),甚至跨程序共享这些信息。这将容许程序和网络基础框架之间相互独立,不会发生干扰。服务器
URLSession 对象中的 configuration 属性,实际上是在进行初始化时 URLSessionConfiguration 对象的拷贝,而且该属性为只读属性。也就是说每一个 URLSession 对象只在初始化时配置 configuration,以后都不会发生改变。cookie
URLSessionConfiguration 有三类工厂方法:网络
default:返回标准的 configuration,使用了全局的磁盘缓存(除了文件下载任务外)、钥匙串中的证书、Cookies。session
ephemeral:相似于default,可是全部的数据都存储在内存中,不会对缓存、Cookie 和证书进行持久化存储。能够将这个配置看做是私有 session,对于实现像秘密浏览功能来讲是很是理想的。闭包
background:该配置会建立一个后台 session。后台 session 不一样于常规状况,它甚至能够在应用程序挂起,退出或者崩溃的状况下运行上传、下载任务。架构
URLSessionConfiguration 还有如:超时时间、缓存策略、Cookie 策略、安全策略等属性的设置,具体的配置选项能够自行查看文档。
URLSessionTask 是一个抽象类,它表示一次网络任务。URLSession 经过建立不一样的 URLSessionTask 对象来处理各类不一样的网络请求任务,因此 URLSessionTask 有多个类型的子类:
URLSessionDataTask:该类用于处理 HTTP 中 GET、POST 方法获取的数据
URLSessionUploadTask:该类用于处理 HTTP 中 POST、PUT 方法上传数据到服务器
URLSessionDownloadTask:该类用于处理从服务器下载文件的网络任务
URLSessionStreamTask:该类用于处理 TCP/IP 链接的网络任务(新增的类型,未使用过。猜想用于视频、IM 类应用)
全部这些任务均可以挂起、开始、取消,下载任务甚至能够实现断点续传。这些 task 得到的数据的处理方式能够经过 completionHandler 闭包或者 delegate 中的方法,可是两者取其一。
Data task 能够经过 URL 或 URLRequest 建立(使用前者至关因而使用一个对于该 URL 进行标准 GET 请求的 URLRequest,这是一种快捷方法)。下面示例为从 itunes 中查询某个关键词的歌曲:
let expectedCharSet = CharacterSet.urlQueryAllowed let searchTerm = searchBar.text!.addingPercentEncoding(withAllowedCharacters: expectedCharSet)! let defaultSession = URLSession.shared let url = URL(string: "https://itunes.apple.com/search?media=music&entity=song&term=\(searchTerm)") dataTask = defaultSession.dataTask(with: url!, completionHandler: { data, response, error in ... }) dataTask?.resume()
上传、下载文件的代码与上面的基本同样,除了新建 dataTask 的类型不一样。
整体来讲苹果对 URLSession 体系的设计这套体系清晰、简洁、高效,也是咱们在平常编码过程须要认真学习的。做为 iOS 程序员除了努力搬砖外,更应该认真对待这些设计思想,不要成为依靠 cocoapods 生存的浮萍。因此在使用轮子的时候,必定不能忘了构建轮子的基本知识,这些基础才是程序员生根的关键。iOS 只不过是代表了当前咱们专一的领域,而程序员才是咱们真正的职业。