Alamofire 源码剖析

Alamofire 是什么?

  • 在功能角度,Alamofire是一个http请求框架。使用它可以很方便的处理http请求(请求数据,下载,上传)。
  • 在代码实现角度,Alamofire是对NSURLSession的封装。
  • 在语言角度可以理解为AlamofireAFNetworking的Swift实现(它们出自同一作者)。

本博文适用对象

在这篇博文我 不会阐述Alamofire的使用方法而是介绍Alamofire的设计思想和组织结构 。希望这篇博文能够抛砖引玉,助你轻松的理解Alamofire的实现细节。

NSURLSession概述

Alamofire是对NSURLSession的封装, 在分析Alamofire前,咱先简单看下NSURLSession的api。

Creating a Session

Configuring a Session

Adding Tasks

  1. Adding Data Tasks to a Session
  2. Adding Download Tasks to a Session
  3. Adding Upload Tasks to a Session
  4. Adding Stream Tasks to a Session

    框架核心:Manager

    Alamofire.swift文件中定义了一组方法以方便我们进行 request, download,upload操作(差不多解决了90%的需求吧)。 这些方法只是为了方便使用,真正做事情的是类ManagerManager才是框架的核心。框架结构如下:

111748276-40ca408f27e20737

Manager.png
  • session: 所有的task都是由这个session创建的,也就是说对session 的配置信息作用于所有的task。
  • delegate: session的代理由专门的类SessionDelegate负责。SessionDelegate实现了 NSURLSessionDelegate, NSURLSessionTaskDelegate,NSURLSessionDataDelegate,
    NSURLSessionDownloadDelegate 协议,并实现了这些协议的所有方法。SessionDelegate就是回调事件的枢纽中心,完成回调的统一处理和散发。
  • backgroundCompletionHandler:当需要执行后台操作任务时使用。具体内容:NSURLSession使用说明及后台工作流程分析
  • AddingTasksMethod:这是一组创建Task的方法。上面 NSURLSession概述 中提到一组 Adding Tasks 方法, 框架对这些方法进行了封装,我们统一称这组方法为AddingTasksMethod。 在后面的 创建Task 部分再细说。
  • startRequestsImmediately:当创建task后,需要调用这个task的resume方法才会开始执行。startRequestsImmediately=true时, 创建好task就会resume。

看下初始化方法:

至此我们已经创建好了session和它的delegate。调用流程大致这个样子: 通过Manager创建sessionSessionDelegate对象——>使用AddingTasksMethod创建task—–>task调用resume()开始执行——>调用SessionDelegate中实现的代理方法。

使用闭包重载代理方法

为了使用框架的灵活性,SessionDelegate为每一个delegate方法声明了一个对应的闭包。这样你就可以很方便的指定如何处理回调。

121748276-fa59b2f339b09542

代理方法对应的闭包.png

例如:

创建Task

框架中对 NSURLSession概述 中的 Adding Tasks 方法进行了封装,组成了前面提到的AddingTasksMethod。

131748276-541e9486d5a18f59

addTaskMethod

request

通过调用下面的方法,创建NSURLSessionDataTask对象。

在上面代码中,URLRequest.URLRequest 就是一个NSMutableURLRequest 对象。我们使用NSMutableURLRequest创建了一个NSURLSessionDataTaskqueue 是串行队列,在串行队列 queue中执行同步方法能够确保创建task时的线程安全。对线程有疑惑的可以看这里GCD 深入理解:第一部分

download

通过调用下面的方法,创建URLSessionDownloadTask对象。 下载包括两种方式:直接下载和断点续传。download方法通过enum对不同类型进行区分。destination 参数是一个闭包,用于在下载结束后确定将下载的文件保存在什么路径。

upload

通过调用下面的方法,创建URLSessionUploadTask对象。 upload分为三种:上传NSData,上传NSURL指定的文件,还有NSInputStream。在upload方法中使用枚举来区分不同的上传内容。 逻辑很简单,不在赘述。

stream

通过下面的方法生成NSURLSessionStreamTask对象。

重构,各司其职

存在的问题

到此总算把各种Task创建出来了。调用Task的resume方法就可以开始执行任务。从服务器返回数据后就会调用SessionDelegate的代理方法。当同时执行多个Task时,我的天,发生了什么。。。 下面就拿NSURLSessionDataTask举例。当多个task同时执行时,他们会交替频繁的调用SessionDelegate代理方法。

141748276-331e66f2fb285b85

Snip20161215_8.png

现在我有下面几个需求:

  • 显示出每个task的执行进度
  • task1得到全部数据后解析成jsonObject, task2得到全部数据后解析成string, task3得到全部数据后解析成propertyList。。。。

创建TaskDelegate及子类,为每个task创建专有的delegate对象

要满足上面的需求,我们必须为每一个task创建一个代理对象,这个代理对象只处理这个task的代理回调。TaskDelegate及子类就是用于做这件事情的。

151748276-5eaf6fe773f8de41

Snip20161215_5.png

执行步骤是这个样子的:

  1. 我们创建了一个创建NSURLSessionDataTask对象dataTask1;
  2. 创建dataTask1对应的DataTaskDelegate对象dataTask1Delegate;
  3. dataTask1获取到数据后调用SessionDelegatepublic func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)
  4. SessionDelegatepublic func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)方法中调用DataTaskDelegatepublic func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)方法。

使用Request封装创建TaskDelegate的过程

为了方便创建TaskDelegate 对象,框架有一个Request类。Request所做的事情就是为每个Task生成对应的TaskDelegate对象。

修改创建Task方法

现在我们需要修改创建Task的方法如下(以request为例):

设置好了之后, 在回调中根据task取出这个task对应的代理对象, 然后执行对应的方法就ok了。

处理响应结果

TaskDelegate类中有串行队列queue:NSOperationQueue,并设置这个队列的queue.suspended = true(添加block不会执行,直到suspended=false) 你可以这个队列中添加要执行的block。在func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) 代理方法中如果error=nil,设置queue.suspended = false。 处理相应结果大致就是这个原理。

写在最后

  • 为了便于理解,在学习框架时画的脑图,相对于文字,脑图结构更加清晰明了。Alamofire框架脑图
  • 虽然写了这么多但还是感觉很多点没有提到。比如说用于对请求参数编码的ParameterEncoding,用于对请求响应数据序列化的ResponseSerialization,用于https验证服务器证书的ServerTrustPolicy, upload操作中对MultipartFormData的具体实现。这些代码质量都很高,值得推荐。
  • 能力有限,难免出现错误。如发现问题希望不吝指教。
  • 写这么多着实占用不少时间,如果对你有帮助,那就给个喜欢吧。
2 2 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部