从零开始打造一个 Swift 网络框架

472 查看

说起网络框架,大家第一时间就会想到 AFNetworking、Alamofire 这些业内响当当的作品,有的老鸟也会适当伤感一下曾经用的 ASI 。这些框架都有一个共同点——功能都很复杂,很齐全,而我们往往只能用到很小很小的一个部分。

事实上,咱们做 App 的时候,绝大多数时候对网络的需求都是收发 GET/POST 请求。就这样来看,根据需求来造个属于自己的轮子,似乎也是个不错的选择。尤其是现在苹果提供的 NSURLSession 已经非常强大,基于原生的 SDK 来做一个自己的框架,其实是很容易的。

根据这个思想,我之前撸了一个简单的网络库 AaHTTP,在工作的项目里重度用了一段时间也没有遇到什么特别的问题。

现在我们就来一步步看看如何做一个属于自己的简单的网络框架。

发送请求的步骤分析

要发送一个请求,分为如下步骤:

  1. 如果携带的参数是 GET 类型,则将参数进行 URL encode(转化为 y1=x1&y2=x2的形式),追加到原始 url 的后面。如果参数是 POST 类型,则 URL 不变。
  2. 用最新的 URL 生成一个 NSMutableURLRequest 的对象
  3. 如果参数是 POST 的情况,设置 Content-Typeapplication/x-www-form-urlencoded, 并将参数进行 URL encode,并添加到 body 中。
  4. 使用 NSURLSession 发送该请求

URL encode时,需要对特殊字符进行转义。

定义发送请求的接口

根据上面的步骤,我们不难一步到位的实现发送请求,新建一个 AaNet.swift (名字您随意),并声明我们的类方法:

我们首先声明了两个函数,request 函数接受的参数依次是:

  • method: 请求类别
  • url: 目标地址
  • form: 参数表
  • success: 成功的回调, 类型为(data:NSData?) -> Void
  • fail: 失败的回调,类型为(error : NSError?) -> Void

第二个函数 buildParams, 输入一个字典,返回一个字符串。很容易想到就是我们用来做 url encode 的函数。

建议大家写代码前,都先写出主要函数的声明和对应的参数、返回值的类型。这其实就是一种最基本的架构工作

实现发送请求

现在按照之前的分析,我们来实现请求发送的逻辑:

整个流程很直观,虽然 GET 参数和 POST 参数处理的位置不同,但都是用我们的 url encode 函数 buildParams 来操作的。区别是 GET 请求的话,处理完后直接 append 到 url 后面,而 POST 需要用 UTF8 encode 一下,放在 request 的 body 里。

然后用 NSURLSession 的默认 session: sharedSession() 来发送请求,并在回调里判断 statusCode 以及 error 对象是否为 nil 来判断请求是否为空,来分别调用我们的 success 回调或 fail 回调。

实现 URL encode

现在我们来实现 buildParams,大体的步骤为:

encode:

  1. 把输入字典转换为键值对的数组。[ (Key,Value) ]
  2. 对于每一个 (key,value),执行:
    2.1 对 key 进行转义,得到 key'
    2.2 检查 value 的类型,如果是简单的值,则对其进行转义,得到 value'。并将 (key' , value') 输出到结果数组中。
    2.3 如果 value 是数组,则用当前的 keyvalue 中的每一个元素组成 tuple: [(key,subValue)], 递归执行步骤2。
    2.4 如果 value 是字典,也先把 value 对应的字段转化为键值对数组,但是 key 的形式为 key[subKey], 前面是 key 是当前的 key,subKey 代表 value 对应的字典中的 key。得到键值对数组后,递归执行步骤2。
  3. 步骤2执行完毕后,我们会得到一个一维的、并且 key 和 value 都被转义过的键值对数组 [ (key,value) ],然后我们将其转换为 key1=value1&key2=value2&...keyN=valueN 的形式返回。

仔细感受一下,步骤2是不是有一个 flat 的过程。

我们先实现转义: