前言:
Alamofire是一个由Swift编写的优雅的网络开发框架。
大部分用Swift编写的iOS App的网络模块都是基于Alamofire的。作为Swift社区最活跃的几个项目之一,有许多开发者在不断的对其进行完善,所以学习这种优秀的开源代码对深入理解Swift的特性很有帮助。
本文很长,大到整个框架的设计,小到某些基础功能的使用都会涉及。
URL Loading System
iOS的网络开发(URL Loading System)的类层次如下:
从图中可以看出,整个框架包括URL Loading相关的核心类和五种辅助类。其中,五种辅助类划分如下
- Configuration 配置信息,比如Cookie的存储策略,TLS版本等等。
- Authentication and Credentials 授权和证书
- Protocol support 用做proxy来拦截或特殊处理某些URL
- Cookie Storage 管理Cookie
- Cache Management 管理缓存
Alamofire就是建立在NSURLSession
上的封装。
NSURLSession
是在2013年推出的新API,并且Apple在2015年废弃了NSURLConnection
。如果你的App还在用以NSURLConnection
建立的网络层(比如AFNetworking 2.x),那么你真的应该考虑升级到NSURLSession(比如AFNetworking 3.x),废弃的API也许还能正常工作,但是Apple已对其不再维护,当然也就不支持HTTP 2.0等新特性。
关于NSURLSesson的基础使用,我之前有过几篇博客,可以在这个链接找到:
那么,用NSURLSession来进行HTTP/HTTPS请求的时候,实际的过程如何呢?
- 建立
NSURLSessionTask
,并且resume
. - 检查cache策略,如果有需要从本地cache中直接返回数据
- 通过DNS进行域名查找
- 建立TCP连接
- 如果是HTTPS,进行TLS握手(如有资源需要认证访问,可能需要客户端提供证书,用户名密码等信息)
- 请求开始,收到HTTP的Response
- 接收HTTP的Data
Tips: 理解HTTP/HTTPS的请求过程很重要,因为往往你需要统计API请求在哪个阶段出了问题,然后对症下药,提高用户体验。
整体架构
Alamofie的整体功能图如下:
其中
- 左侧是暴露给外部的接口,右侧是内部实现相关
- 这三个模块比较独立:AlamofireImage 和 AlamofireNetworkActivityIndicator 是基于Alamofire开发的独立的库,分别用来做图片和网络状态小菊花,
NetworkReachabilityManager
也是先对独立的用来检测蜂窝移动,WIFI等网络变化的。
我们先从一个API调用切入,来分析各个模块的作用:
Alamofire.request(/**/).validate(/**/).responseJSON {
/**/}
初始化SessionManager的单例default
//整理后代码
self.delegate = SessionDelegate()
self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
在初始化SessionManager
代码里,提供了一个默认的SessionDelegate,并且初始化了一个URLSession,这个URLSession的delegate是SessionDelegate。
通过这个初始化,我们知道URLSession的几个代理事件都是传递给SessionManager的SessionDelegate了。
执行全局方法Alamofire.request
方法体中调用SessionManager.default单例的实例方法来创建DataRequest
。这一步做了如下动作:
- 根据传入的url,parameters等参数创建
URLRequest
- 根据
URLRequest
和SessionManager
的属性session(URLSession)
,adapter
(请求适配器),queue
(GCD queue)创建URLSessionDataTask
- 根据基类
Request
提供的方法,创建子类DataRequest
实例,并且为子类DataRequest
初始化一个DataTaskDelegate
。
每一个DataRequest对应一个DataTaskDelegate,每一个TaskDelegate有一个OperationQueue,这个queue在初始化的时候是挂起状态的,并且是一个串行队列(maxConcurrentOperationCount = 1)。
open class Request{
init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
self.session = session
switch requestTask {
case .data(let originalTask, let task):
taskDelegate = DataTaskDelegate(task: task)
self.originalTask = originalTask
//省略
}
delegate.error = error
delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() } //加入统计请求结束的Operation
}
}
- 按需执行DataTask的resume方法
执行DataTask.validate
内容很简单,就是把传入的闭包保存起来,等待后续执行,并且返回Self
执行DataTask.responseJSON
在这个方法里,创建一个NSOperation加入到DataTaskDelegate
的queue中,这个queue在创建之初是刮挂起状态的,所以提交的任务不会执行。
URLSession收到数据
首先SessionDelegate代理方法被调用:
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
if let dataTaskDidReceiveData = dataTaskDidReceiveData {
//有自定义实现
dataTaskDidReceiveData(session, dataTask, data)
} else if let delegate = self[dataTask]?.delegate as? DataTaskDelegate {
//走默认实现
delegate.urlSession(session, dataTask: dataTask, didReceive: data)
}
}
在这个代