Alamofire源码分析笔记

Alamofire

1. Alamofire结构

Alamofire全部实现共有17个文件组成,如下:

--------接口----------
Alamofire.swift // api 声明

--------请求----------
Request.swift // 请求类,用于构建请求
ParameterEncoding.swift // 参数编码
MultipartFormData.swift // 自定义表单类
ServerTrustPolicy.swift // 服务器验证

--------响应-----------
Response.swift // 相应类,用于构建响应
ResponseSerialization.swift // 响应数据序列化
Validation.swift // 响应数据验证
Result.swift // 请求结果表示
AFError.swift // 错误类型

--------底层-----------
SessionManager.swift // 请求session的管理类,底层使用NSURLSession实现
SessionDelegate.swift // 请求Session的代理对象,主要实现NSURLSession的代理方法以及回调闭包
TaskDelegate.swift // 请求Task任务的代理对象,主要实现NSURLDataTask的代理方法
DispatchQueue+Alamofire.swift //GCD扩展,定义多个不同功能的队列

---------其他-----------
NetworkReachabilityManager.swift // 网络状态监听类
Notifications.swift // 定义通知
Timeline.swift //描述请求有关的时间 结构体

Alamofire有五模块组成,即接口、请求、响应、底层和其他。分析各模块的实现,功能和联系就可以理解Alamofire。

2. Alamofire源码分析

2.1 Alamofire.swift文件

查看源码可以发现分为两部分:

  • 一部分主要是协议的定义和相关URL转换,如String,URL,URLComponent转URL,并且抛出异常。
  • 另一部分,定义公开的接口,分别是数据请求(Data Request)、下载请求(Download Request)、上传请求(Upload Request)和流传输请求(Stream Request)。

主要分析第二部分:

  • @discardableResult 作用忽略返回值警告。
  • 所有方法的调用都需要使用SessionManager.default.xxx。这说明SessionManager是所有请求的入口和管理中心。
  • 每个请求都会返回XXXRequest对象,关于XXXRequest对象,在后面会分析。

2.2 Request.swift文件

上面提到每个请求的返回值都是XXXRequest类型。

Request.swift文件中定义了五个类,分别是Request、DataRequest、DownloadRequest、UploadRequest和StreamRequest。其中Request为基类。

2.2.1 Request类

基类Request,定义了与HTTP请求相关的属性和方法。

  • 属性 :代理delegate(TaskDelegate)和Foundation框架中与URL请求相关的四个属性,分别是task(URLSessionTask)、session(URLSession)、request(URLRequest)和response(HTTPURLResponse)。除此之外,还有重试请求次数retryCount、请求开始时间startTime和结束时间endTime,以及验证闭包validations。
  • 方法 :基类Request提供初始化方法init(session: URLSession, requestTask: RequestTask, error: Error? = nil)默认访问权限internal,一般是SessionManager调用创建request,外部不需要创建。另外还有三个服务器验证和三个请求状态的方法resume()suspend()cancel(),其作用是调用成员属性task和发送对应的通知,如Notification.Name.Task.DidResume。
  • 其他 :另外,还有实现了两个协议CustomStringConvertibleCustomDebugStringConvertible。前者定义description包含了http方法、url和响应状态码,后者是比较具体的debug。

2.2.2 DataRequest类

子类DataRequest,管理底层的URLSessionDataTask。主要用于简单的HTTP请求,GET和POST等。

  • 属性 :其中包含三个属性,request(URLRequest)、progress和dataDelegate,其中dataDelegate必须向下转换(as!)为DataTaskDelegate类型。
  • 方法 : 另外,还有两个方法 open func stream(closure: ((Data) -> Void)? = nil) -> Selfopen func downloadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self 分别用来设置流闭包和下载进度闭包操作。

2.2.3 DownloadRequest类

子类DownloadRequest,管理底层URLSessionDownloadTask。实现下载请求。包含三个部分辅助类型、属性、和方法。

  • 辅助类型 : DownloadOption(OptionSet)用于移动下载文件从临时URL到目标URL。闭包类型DownloadFileDestination决定下载请求完成后临时文件写入的位置。两个参数:临时文件URL和URL Response。两个返回值参数:目标URL和定义如何移动(DownloadOptions)。枚举类型Downloadable。
  • 属性 :request(URLRequest)、resumeData(暂停或者失败,用于重新开启)、progress(下载进度)和 downloadDelegate(下载代理)。
  • 方法open override func cancel()open func downloadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self。前者用于取消下载,后者设置下载过程的闭包和执行队列。

2.2.4 UploadRequest类

上传请求,DataRequest的子类。三个属性,一个方法。

  • 属性 : request(URLRequest)、uploadPregress(上传进度)和uploadDelegate(上传代理)
  • 方法open func uploadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self 后者设置上传过程的闭包和执行队列。

2.2.5 StreamRequest类

流请求,没有定义属性和方法,是Request的子类。

2.2.6 对比

对比四个子类,他们对应普通请求、下载请求、上传请求和流传输请求。我们注意到一些相似之处,

  • 他们都有遵循TaskConvertble协议的枚举类型。 其中唯一的方法:task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask ,用于创建对应的task,并对urlRequest做适配。
  • Request的delegate/taskDelegate与各个子类中的XXXTaskDelegate的作用是相同的,就是用于创建TaskDelegate.swift文件中的各种代理实例,用来处理URLSessionDelegate的请求。稍后我们在分析TaskDelegate.swift

2.3 ParameterEncoding.swift文件

由名字可以理解该文件负责对请求参数进行转码,如:URL转码、JSON转码和PropertyList转码。三种转码对应三个结构体:URLEncodingJSONEncodingPropertyListEncoding。他们都遵循ParameterEncoding协议。协议只有一个方法:func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest, 把参数转成目标格式,另外还设置HTTP头部的信息。例如Content-Type:application/json

2.4 MultipartFormData.swift文件

构建用于在HTTP或HTTPS主体中上传的multipart/form-data。 目前有两种编码多部分表单数据的方式。 第一种方法是直接在内存中编码数据。 这是非常有效的,但如果数据集太大,可能会导致内存问题。 第二种方式是设计用于较大的数据集,并将所有数据写入磁盘上的单个文件,并具有所有正确的边界分割。 第二种方法必须用于较大的数据集,如视频内容,否则,当您尝试对数据集进行编码时,应用程序可能会耗尽内存。
有关multipart/form-data的更多信息,请参考RFC-2388和RFC-2045规范以及w3表单文档。

涉及到的知识比较深,需要补充一下。开个坑,以后填!

2.5 ServerTrustPolicy.swift文件

服务器验证。开个坑,以后填!

2.6 Response.swift文件

Response.swift中,有四个结构体,分别是DefaultDataResponse/DataResponse, DefaultDownloadResponse/DownloadResponse。 其中Default是未经格式化的。前两个用于普通数据请求和上传,后俩个用于下载。主要功能是存储响应相关值。

2.6.1 DefaultDataResponse/DataResponse结构体

  • s属性 :有五个属性request(URLRequest)、response(HTTPURLResponse)、data(返回的数据)、error(请求错误信息)和timeline(请求时间线,对应Timeline.swift)。
  • DataResponseDefaultDataResponse多两个属性:value(result.value)和result(序列化数据)。其他属性相同。

2.6.2 DefaultDownloadResponse/DownloadResponse结构体

  • 属性 : 有七个属性,request(URLRequest)、response(HTTPURLResponse)、temporaryURL(临时地址)、destinationURL(最终地址/重定向地址)、resumeData(下载取消时的contentOffset)、error(请求错误信息)和timeline(请求时间线,对应Timeline.swift)
  • DownloadResponse同样多了两个属性。

2.6.3 对比

无论是DataResponse还是DownloadResponse都有两个方法:public func map<T>(_ transform: (Value) -> T) -> XXXResponse<T>public func flatMap<T>(_ transform: (Value) throws -> T) -> XXXResponse<T>用于数据转化,区别在于后者会抛出异常。无论是服务器原始数据,还是序列化后的数据,都会被存放在result枚举的case绑定的元组中,success为泛型,failure为Error。具体内容后面在Result.swift中讲解。

2.7 ResponseSerialization.swift文件

查看源码,文件由两个协议、两个结构体和多个extension组成。

--------协议---------
1. DataResponseSerializerProtocol
2. DownloadResponseSerializerProtocol

--------结构体--------
1. DataResponseSerializer<Value>
2. DownloadResponseSerializer<Value>

--------Request扩展------
0. Timeline
1. Default
2. Data
3. String
4. JSON
5. Property List

  • Request扩展中2-5都依赖于扩展1的方法,底层调用构造response,几种序列化过程基本相同。

具体内容,后期补充。

2.8 Result.swift

一个枚举类型Result,有两个case: successfailure

  • success: 绑定指定的泛型实例
  • fialure: 绑定Error

两个主要的方法

  • public func map<T>(_ transform: (Value) -> T) -> Result<T>
  • public func flatMap<T>(_ transform: (Value) throws -> T) -> Result<T>

两者区别,前者不会抛出一样。

2.9 AFError.swift

枚举类型AFError,包含四个内部枚举:

* ParameterEncodingFailureReason // 参数编码错误
* MultipartEncodingFailureReason // 表单错误
* ResponseValidationFailureReason // 响应验证错误
* ResponseSerializationFailureReason // 数据序列化错误

除了四个内部枚举外,AFError本身还有一个,URL无效错误。

另外,还可以通过布尔值判断是否有错误。

AFError.swift涉及到内联枚举,枚举绑定值和提取判断等。

2.10 Validation.swift

Validation.swift主要用于服务器响应数据验证。

由三个扩展组成: Request扩展,DataRequest扩展,DownloadRequest扩展。第一个是基本验证,后两个是对不同的下载需求的验证。

接下来,看看具体实现了什么?

Request扩展

  • 两个属性,分别是acceptableStatusCodesacceptableContentTypes
  • 两个方法,分别是fileprivate func validate<S: Sequence>( statusCode acceptableStatusCodes: S, response: HTTPURLResponse) -> ValidationResult where S.Iterator.Element == Int

    fileprivate func validate<S: Sequence>( contentType acceptableContentTypes: S, response: HTTPURLResponse, data: Data?) -> ValidationResult where S.Iterator.Element == String
    这两个属性和方法分别用于验证StatusCode和ContentType。

DataRequest扩展

四个方法:

  • validate(_:) : 基础方法,接收Validation类型闭包,构建validationExecution,添加到验证队列中。
  • validate(statusCode:): 验证StatusCode
  • validate(contentType:):验证ContentType
  • validate():同时验证StatusCode和ContentType

2.11 SessionManager.swift/SessionDelegate.swift/TaskDelegate.swift

  • SessionManager负责Session的创建和管理,请求的创建和发起
  • SessionDelegate/TaskDelegate负责处理请求的响应

SessionManager共有10个属性,主要的几个:

  • default : 一个单例,对外的接口都调用这个实例。
  • defaultHTTPHeader: 请求头,定义了默认HTTP头部信息
  • backgroundCompletionHandler: APP进入后台时完成的闭包,需要手动设置和调用。
  • queue: 每个Session私有的任务队列

接下来是初始化方法,SessionManager初始化过程:

  • 1.调用者通过func request(_ urlRequest: URLRequestConvertible) -> DataRequest方法调用
  • 2.SessionManager通过传入urlRequest创建适配的urlRequest(Request适配器)
  • 3.调用Request.Requestable.task(:::)创建对应SessionTask
  • 4.创建对应的XXXRequest实例
  • 5.将XXXRequest设置到Delegate[task]下标
  • 6.开始任务

另外,还有错误处理,重试等内容。

补充

1. URL Loading System架构

URL Loading System

URL加载系统包括加载URL的类,以及一些重要的帮助类。主要的帮助类:协议支持,身份验证和凭据,Cookie存储,配置管理和缓存管理等。

小结

初步学习了Alamofire源码文件,并没有深入探究源码具体实现。后续内容稍后补充,先补补基础知识。🤣

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • Alamofire源码解读 AFNetworking的作者Matt Thompson 提出了一个新的类似AFNet...
    spicyShrimp阅读 1,129评论 0 3
  • Alamofire的基本用法 1.请求 这是一个最简单的请求,这个请求即不需要参数,也不需要接收数据。接下来我们翻...
    水落斜阳阅读 3,200评论 0 16
  • Alamofire 是一款 Swift 写的 HTTP 网络请求库 前言 本篇内容为 Alamofire 官方 R...
    zongmumask阅读 20,659评论 6 66
  • 7月6日 星期四 晴 上班的人参加特训营真是伤不起,真想把时间掰成两半来用!做完作业其实想让自己锻炼一下,参加P...
    雪媚阅读 358评论 0 0
  • 今天我们share一个超好用了洁面方法。 操作难度 ★★ 清洁指数 ★★★★ 耗费时间 ★★★ 适用人群:主要针对...
    麦小琪阅读 378评论 0 0