iOS开发之Alamofire源码深度解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介:

一.Alamofire核心模块概述

我们先整体上来看一下AlamoFire这个框架关系,概述一些核心模块。该部分我们先来看一下AlamoFire的文件组织结构,然后在给出这些文件组织结构中类的关系。所以在本部分类图是少不了的。废话少说,进入该部分的主题。

1.Alamofire的目录结构解析

首先我们来看一下AlamoFire的目录结构,从整体上来把控一下AlamoFire。下方截图是AlamoFire框架的所有文件,文件不算多,Alamofire框架的源代码并不算多,所有理清Alamofire的框架结构还是不难的。下方截图中是AlamoFire中的所有文件,Core文件夹下是Alamofire的核心文件,Features主要是对核心文件的扩展。今天我们就以核心文件为主,Feature文件为辅来窥探一下AlamoFire框架的源码。

下方是对Core文件夹下的各个文件的功能简述:

  • Alamofire.swift ---- 该文件中主要是给用户提供一些便利的调用方法,用户可以直接调用该文件中的便利方法来使用Alamofire相关功能。
  • Manager.swift ---- Manager中定义了Session对象,Session相关的Delegate,以及Delegate执行的队列等相关信息,在Manager中创建Request对象发起请求。Manager管理的就是各种请求,Manager对象是以单例的形式对外开放的。
  • Request.swift ---- 该文件如其名,就是负责创建Session的各种task的,并执行相关的SessionTask,并调用相关书籍解析的功能模块对数据进行解析并通过回调返回给用户。
  • ParameterEncoding.swift ---- 负责请求参数的各种编码(URL、URLEncodedInURL、JSON、PropertyList等编码),并将编码后的数据与URLRequest结合后的结果进行返回。
  • Result.swift ---- 对解析后的数据封装成Result对象。
  • Response.swift ---- 负责将服务器相应的数据进行封装生成Response对象,该对象中就包括上述的Result对象,用户最终会通过闭包回调的形式获取到该Response的对象。
  • Notifications.swift ---- 其中是一个Notification结构体,该结构体中定义了一些字符串,这些字符串就是所需通知的Key,当网络请求DidResume、DidSuspend、DidCancel、DidComplete都会发出通知。
  • Error.swift ---- 其中是一个Error的结构体,其中封装的是各种错误状态。

Features文件夹下各个文件的功能简述:

  • Download.swift ----- 对Manager和Request类进行扩展,使其支持Down Task,其中封装了NSURLSessionDownloadDelegate相关代理方法。
  • Upload.swift ---- 在该文件中也是对Manager和Request类进行的扩展,使其支持Upload Task,其中封装了NSURLSessionDataDelegate中获取上传数据进度的代理方法,也就是taskDidSendBodyData代理方法。
  • MultipartFormData.swift ---- 该文件从名字就可以看出是为了组织多表单数据上传的数据的,在Upload Task中就使用到了MultipartFormData。
  • Stream.swift ---- 和Download和Upload文件相似,该文件中也是对Manager和Rquest做延展,主要使其支持数据流的传输,其中主要封装和实现了NSURLSessionStreamDelegate相关的代理方法。
  • ResponseSerialization.swift ---- 该文件中主要是对Request类进行数据解析的延展的。其中封装了各种对响应数据的解析方式,其中包括Data、String、JSON、PropertyList等解析方式。
  • NetworkReachabilityManager.swift ---- 该文件主要是对SystemConfiguration.framework中的SCNetworkReachability相关的东西进行封装的,主要用来管理和监听网络状态的变化。
  • ServerTrustPolicy.swift ---- 这个文件主要是对NSURLSession做的延展,其中定义了各种网络请求的认证策略,主要证书认证相关东西。
  • Timeline.swift ---- 该文件是为了方便调试而生的,其中记录了相关操作的时间点,并且对其进行记录,便于在Debug时使用到。
  • Validation.swift ---- 主要是用来验证请求是否成功,如果出错了就做相应的处理。

上面是AlamoFire中所有文件的概述,上面这些算是对AlamoFire框架有大概的了解吧。结合上方的概述,来研读AlamoFire源码还是比较清晰的。下方就是AlamoFire 3.4中相关文件的木头结构,如下所示:

  

 

2.核心类间的结构

上面简单的介绍了Alamofire框架的目录结构以及每个文件所负责的内容。接下来我们进入到各个文件的内部,来整体的看一下核心类之间的关系。下方是核心类的“类图”,当然下方只是核心类的。接下来来概述一下下方的类图,因为下图太大,在此看起来不太清楚,如果你感兴趣,你可以另存为,然后放大查看。

  • 下方黑框中的部分对应的就是Alamofire.swift中的内容。其中主要是一些URL转换字符串的延展以及URLRequst转换成MutableURLRequest的延展,还有一些用户使用的便利方法。
  • 黄框中就是我们Manager.swift中的内容了,Manager类的对象是以单例的形式对外展现的,上述黑框中的便利方法,主要是获取Manager类的单例,然后调用相应的方法。
  • 绿框中所对应的主要是Request.Swift和Features文件夹中的内容,主要是Request类及其延展,当然还有对Manager和NSURLSession的延展。
  • 红框中的就是网络请求会话的各种任务的回调方法的封装了,在这些回调方法中提供了默认实现,并对外留有回调块,以便让用户来自己实现这些回调方法。

  

 

二、Alamofire.swift源码解析

第一部分算是概览了一下Alamofire框架中的各个组成部分,接下来该进入到上述的各个模块中来进一步来窥探其实现和组织方式了。还是“顺藤摸瓜”,先从用户看的到的地方着手,然后层层深入,直到你看不见的地方。所以第二部分我们先来看一下Alamofire.swift中的内容,因为该文件是Alamofire框架的入口。

1.Alamofire.swft中的类图结构

下方的类图就是第一部分类图中黑框的放大版,根据Alamofire.swift这个文件我们不难画出下方这个类图。有一点要说明的就是在类图中省略了一些遍历方法,只写了一些主要的,不过核心的功能还是有的。下方的URLStringConvertible和URLRequestConvertible是负责类型转换的接口,具体的请看下方的介绍。该文件中除了类型转换的方法外就是一些调用Manager的单例的便利方法了。

  

2.Alamofire.swift技术细节

下方就是URLStringConvertible协议以及相关延展的具体实现,主要功能就是将String、NSURL、NSURLComponents、NSURLRequest中的URL转换成字符串类型。将要转换的类型要遵循URLStringConvertible协议,并在计算变量URLString中返回转换后的字符串。具体做法如下所示,这中类型转换方式在开发中经常会使用到,下方会给出其他实例。URLRequestConvertible协议的功能与URLStringConvertible大同小异,URLRequestConvertible协议的实现者负责将NSURLRequest转换成NSMutableURLRequest类型。在此就不做过多的赘述了。

  

下方截图是Alamofire.swift中的一个便利方法,其他几个便利方法与此相似,都是调用Manager单例中相应的方法,便利方法为了链式调用Request类中的相关方法,所以所有的便利方法都会返回当前Manager单例使用的Request对象。具体如下所示:

  

 

3.扩展用例

学以致用,举一反三。上面那种“面向协议”开发的思想值得我们学习,之前在设计模式相关的系列博客中不止一次的提到过要“面向接口编程”,此处的协议就是接口。虽然上面只是使用协议来进行简单的类型转换,这种思想是非常值得我们学习的。通过上面类型转换的方式,我们可以写出下方代码。下方代码不是Alamofire框架中的代码,是我根据上述的类型转换的实例所实现的,下方定义了一个类型转换的协议,需要转换的类型要遵循这个协议,下方以String为例,具体做法如下所示。

  

 

三、Manager.swift源码解析

因为便利方法主要是调用的Manager类的单例,所以接下来我们来看Manager.swift中的东西。Manager类中主要负责Session和Request的初始化,并且提供SessionDelegate代理方法的默认实现。在实现代理方法时留出了相应的闭包已提供给用户使用该闭包来回调相应的代理方法。在Manager中的SessionDelegate类就是NSURLSessionDelegate以及相关子协议的代理类 ,其中就给出了各个代理方法的默认实现,在实现时并定义了一系列的Closure回调变量,当这些闭包变量不为空时就会执行闭包块中的内容,而不会执行提供的默认实现。

1.Manager.swift相关类图

下方类图就是黄色部分的放大版,主要是Manager类与SessionDelegate的关系。从下方类图中不难看出,SessionDelegate类遵循了NSURLSessionDelegate协议以及子协议,并给出了代理相应的实现方法。下方的代码会给出代理的具体封装和实现方式。

  

 

2.Manager类的相关属性

开门见山,因为Manager类对外是以单例的形式对外使用的,所以我们先来看看Manager类的单例实现。下方截图中的sharedInstance计算属性就是Manager的单例,其中存储的就是一个Manager对象,在创建Manager对象时我们为Manager对象中存储的NSURLSession对象指定了一个defaultSessionConfiguration和一个defaultHTTPHeaders。

  

上面是Manager类中单例的实现,接下来我们来解析类中核心的属性,下方是一些核心属性的解析:

  • defaultHTTPHeaders属性 : defaultHTTPHeaders是Manager类中的一个计算属性,负责组织默认的请求Header中的内容。
  • session属性: 该属性的类型是NSURLSession类型的,负责请求会话,并创建各种会话任务。
  • queue属性:该属性是一个串行队列,该队列负责执行session创建Session Task的任务。
  • delegate属性:该属性是SessionDelegate类型的,而SessionDelegate类遵循了NSURLSessionDelegate及其子协议,并给出了相应的实现,在下方会着重介绍SessionDelegate。而此处的delegate属性负责调用SessionDelegate类中相应的回调方法。

 

3.Manager类的request方法

在Manager.swift源文件中给出了request方法的实现,Manager类的单例所调用的upload、download等方法是在其他源文件中做的延展。那些延展中的方法稍后在聊,本部分中就先对request方法进行解析。下方的方法就是我们在便利方法中使用Manager类的单例所调用的方法。method参数表示请求方式(GET, POST, PUT等),URLString参数是请求地址,parameter就是请求参数了。encoding参数就是请求参数的编码方式,此处默认是URL编码。headers字典参数就是请求头信息了,默认为nil。下方代码主要是创建NSMutableURLRequest对象,然后将参数进行相应的编码后添加进NSMutableURLRequest对象中,然后调用request()方法发起请求。

  

下方代码段是上述函数中所调用的request()方法,下方的request()方法负责通过Session创建dataTask,也就是负责执行Data Task任务。然后在初始化Request类的对象时,将创建的Data Task对象传给Request对象。然后将Request对象的 Task Delegate对象存入Manager类的delegate属性中。因为在delegate属性中的代理方法是调用相应的Task Delegate的方法,所以在此有必要进行存储。然后调用Request对象的resume()方法发起数据的网络请求。为了链式调用Request对象的其他方法,所以将Request类的对象进行返回。代码如下所示:

  

 

4. Manager中SessionDelegate解析

SessionDelegate可以说是代理的代理,因为在SessionDelegate中有一个subdelegates字典属性,该属性负责存储Request对象中的各个Task Delegate。而SessionDelegate在相应的代理方法中会通过存储的Task Delegate来调用Task Delegate中的方法,所以SessionDelegate说是代理的代理。

下方代码段是SessionDelegate类中部分代码的截图,其中的subdelegates字典属性中存储的就是Request中的TaskDelegate,subdelegateQueue是一个并行队列用来同步执行获取和设置字典中的Task Delegate对象。然后就是为SessionDelegate类定义了一个下标,该下标的功能是以Session Task为下标的形式向subdelegates中添加和获取相应的Task Delegate。该自定义下标就可以让类的对象使用下标的形式来设置和获取属性的值,稍后会给出扩展的Demo。

  

关于SessionDelegate中所实现的代理方法,在此我们就一执行Data Task请求的didReceiveData代理方法为例。下方截图就是SessionDelegate中的didReceiveData代理方法。代码比较简单,首先判断该代理方法对象的Closure回调变量是否有值,如果有就执行该闭包回调块,如果没有值就获取我们存储的Data Task Delegate, 然后去执行Data Task Delegate中的didReciveData方法。其他方法也于此类似,所以就以点代面,在此就不做过多的赘述了。

 

5.知识点扩展

接下来有到了举一反三,扩展知识点的时刻了。接下来我们单独来创建一个小实例来看一下Swift中自定义下标是怎么回事。大道至简,接下来我们将上述下标的使用进行简化,创建一个Demo, 然后通过这个Demo来介绍一下下标的使用。

下方代码段就是我们创建的简化版的下标示例,在Swift的类中是支持自定义下标的,自定下标可以让你以下标的形式来访问和设置属性。下方就自定义了一个下标,在下标中设置和返回value属性的值。用法如下所示:

  

 

四、Request.swift源码解析

逐渐深入,我们现在来到了Request.swift这个类,因为上面的Manager中的请求最终走到了Request类的位置,所以接下来我们要分析的就是Request.swift源文件中的内容。Request.swift源文件中主要是执行的Data Task请求,并且实现了相应的Data Task Delegate中的方法。其他的任务例如Download Task, Upload Task,Stream Task等会在其他文件中对Request做延展时执行上述这些任务。我们在此就以Data Task为例。Request类中说白了就是负责通过会话创建相应的Task,并实现相应Task的代理方法。

1. Request相关类图

下方类图就是Request相关类图了,Request类及其延展中就是创建各种类型的Task,然后给出相应的Task Delegate。下方类图还给出个各种Task Delegate间的继承关系。Request相关源文件在给出TaskDelegate的代理方法的实现时,也封装了闭包状态下的回调方法。这中做法与SessionDelegate中做法一致。下方会给出具体的介绍。

  

 

2.Request类的初始化方法

下方就是Request类的初始化方法,方法需要两个参数,第一个参数是NSURLSession的对象,该对象也就是Manager单例中创建的Session的对象。而第二个参数虽然是Manager传过来的,但是初始化task的任务还得交给Request类来做,Manager来只不过是定义了一个NSURLSessionTask的类型传到了Request中,例如在Manager的request()方法中task是NSURLSessionDataTask,Manager的upload()方法中的task是NSURLSessionUploadTask类型。

在Request的初始化方法中根据Manager单例提供的task的类型来确定是创建DataTaskDelegate、UploadTaskDelegate等。在相应的Task Delegate中会创建相应的Task。我们还以上述的DataTask为例,如果你调用Manager单例中的request()方法就会执行下方的DataTaskDelegate()的初始化。如下所示:

  

上面的delegate是TaskDelegate类型的,因为UploadTaskDelegate、DownloadTaskDelegate以及DataTaskDelegate都是TaskDelegate的子类,所以此处用到了面向对象的“多态性”。下方两个属性就是Request类中的delegate和task属性,delegate的初始化在上述Requset的初始化方法中,而此处的task是一个存储属性,task的初始化是放在相应的TaskDelegate中的,在TaskDelegate中创建完task对象后再赋值给Request类中的task属性,如下所示:

  

 

3. Requset类中的Progress闭包

在使用Request类的对象时,我们可以链式的调用Request中的方法,最常用的就是获取相应任务执行的进度,也就是平时我使用的progress()方法。下方截图中的代码段就是progress()方法的实现。通过Task Delegate的类型来判断目前执行的哪种任务,然后将传过来的progress的闭包赋值给相应的Task Delegate,在这些Task的Delegate中会在相应的回调方法中获取任务执行进度,然后执行下方传入的Closure。

  

 

4.Request的resume()方法

下方就是Request类中的resume()方法,其中的代码比较简单。主要是用来记录startTime,然后调用task的resume方法开始执行任务。当然在开始执行任务后要发起相应的通知,此处发出的是DidResume通知。所有的通知类型都在Notifications.swift文件中的Notifications结构体中存储着。Request类中的其他方法,比如suspend()、cancel()方法的实现方式与resume()类似,并且都会发出相应的通知,在此就不做过多的赘述了。

   

 

5.Request类中的相关代理类

从第一部分中的类图中我们能看出与Request类相关的代理类,TaskDelegate是所有代理类的基类。在该代理类中其实就是定义了一下必要的属性和NSURLSessionTaskDelegate中对应的回调方法,并且为这些回调方法提供相应的闭包回调的形式。此处就以TaskDelegate代理类为例。下方就是TaskDelegate代理类为NSURLSessionTaskDelegate中相应的代理方法提供的Closure方式。其他的代理类如DataTaskDelegate、DownloadTaskDelegate等与此类似。而相应的代理方法中就是对回调进行了处理,不过在处理之前会判断相应的Closure是否为nil, 如果不为nil的话就执行Closure闭包块中的内容。如果为nil,就执行提供的默认处理。

  

 

事无巨细,至此Alamofire中的核心类就已经介绍完毕,因为篇幅有限,其他类在此就不做过多赘述了。其他类以及其他文件中的内容在第一部分中做了概述,其内部的实现细节就不做过多赘述了,在Github上分享的代码对这些类的关键技术细节给出了注释。

在Alamofire框架中大量的使用了延展、闭包以及枚举关联值。特别是在解析网络请求的数据时,将闭包类型作为函数的参数,然后通过闭包变量来提供相应的解析方案,在此就不做过多的赘述了,其他技术细节“仁者见仁,智者见智”。听我说再多,看再多的技术博客如果不亲自的去了解一下,说再多也是没用的,实践出真知。




      本文转自zsdnr  51CTO博客,原文链接:http://blog.51cto.com/12942149/1929665,如需转载请自行联系原作者








相关文章
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
14 2
|
3天前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
16天前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
36 3
|
9天前
|
开发工具 Android开发 数据安全/隐私保护
探索移动应用的世界:从开发到操作系统的全面解析
【10月更文挑战第33天】在数字化时代,移动应用已成为我们日常生活中不可或缺的一部分。本文将深入探讨移动应用的开发过程,包括编程语言、开发工具和框架的选择,以及如何构建用户友好的界面。同时,我们还将分析移动操作系统的核心功能和安全性,以帮助读者更好地理解这些应用程序是如何在各种设备上运行的。无论你是开发者还是普通用户,这篇文章都将为你揭示移动应用背后的奥秘。
|
16天前
|
机器学习/深度学习 Android开发 UED
移动应用与系统:从开发到优化的全面解析
【10月更文挑战第25天】 在数字化时代,移动应用已成为我们生活的重要组成部分。本文将深入探讨移动应用的开发过程、移动操作系统的角色,以及如何对移动应用进行优化以提高用户体验和性能。我们将通过分析具体案例,揭示移动应用成功的关键因素,并提供实用的开发和优化策略。
|
17天前
|
安全 5G Android开发
安卓与iOS的较量:技术深度解析
【10月更文挑战第24天】 在移动操作系统领域,安卓和iOS无疑是两大巨头。本文将深入探讨这两个系统的技术特点、优势和不足,以及它们在未来可能的发展方向。我们将通过对比分析,帮助读者更好地理解这两个系统的本质和内涵,从而引发对移动操作系统未来发展的深思。
33 0
|
1月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
66 0
|
1月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
52 0
|
1月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
60 0
|
1月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
80 0

推荐镜像

更多