Swift中的网络层

如何避免经常被称为NetworkManager的Big-Fat-Singleton™并快乐地生活

在此链接中可以找到 本文的新更新版本

作为开发人员,每次启动新项目时,我们都会编写,重写和重构大量内容。
有时有充分的理由来进行这类活动(想想Swift和Obj-C中的面向协议的编程 ),更经常的是,我们继续开心地做一些我们认为很干净的代码,有意识地忽略了时间的客观损失( … 直到我们开始下一个项目 )。

这些有趣的活动之一涉及软件的网络层。
所有应用程序中有99.99%会在某个时刻与Internet通讯,因此这是所有软件的关键点。
这些年来,我已经看到并编写了许多不同的网络层。 除了一些罕见的情况外,大多数情况都是作为一个称为NetworkManager的巨大单例类(或类似的东西)实现的,该类具有有关网络内容的程序的全部知识。

所有应用程序中有99.99%会在某个时刻与Internet通讯,因此这是所有软件的关键点。

在我之前的工作中,有一个大型的企业计划-目标是完成一个不完整的代码并将其投入生产:我花了一个多星期的时间来摆脱这个庞大的怪物(我喜欢称之为FNMFatNetworkManager ),使它“更小”; 范围是同时支持两个不同的用户会话(一个用于应用程序本身,另一个用于手表配套应用程序),因此,单个实体不仅是设计问题,还是实际问题。

即使这种单例方法通常可以毫无问题地工作,但在良好的软件设计原则之一中,它很少会失败:单一职责。

在本文中,我将通过分离网络工作流的每个步骤来为该问题提供一个可能的解决方案。
但是,首先,关于SRP只需几句话。

SOLID中的S:单一职责

无论我们认为什么是出色的代码,它始终需要一种简单的质量:代码必须是可维护的。 任何无法维护并且不能相对轻松地适应不断变化的需求的代码就是等待变得难以管理然后过时的代码。

SRP是SOLID原则的一部分( 单一职责 开闭 liskov替换 接口隔离 依赖项倒置 )。 虽然我们没有足够的时间来展示每个人,但是第一个字母S代表单一责任原则 ,其重要性不能被夸大:在任何编写不佳的代码中,您总是可以找到一个承担多个责任的类。

在任何编写不佳的代码中,您总是可以找到一个承担多个责任的类

我的FNM违反了SPR(… 几乎到处都是 ):它了解有关连接的所有信息(基本url,每个请求的路径),如何构建和执行每个请求,如何解析响应数据以及最终还管理内部用户会话以及一些其他内容。用户的个人资料数据(一场噩梦!)。 与网络连接相关的所有内容都位于这个庞大的单例类中。
而且,尽管我并不是说单例不一定很坏,但也不能将它们作为依赖项注入,也不能为测试目的而轻易地模拟它们。

我们可以做得更好……如何?

如我们所见,绝大多数网络层架构如下所示:

为了分离责任,我们需要通过创建几个状态来破坏怪物,每个状态实现工作流程的单个步骤。
这使我们能够分离问题并创建工作流,在此我们还可以注入模拟数据来执行测试。

我们可以将网络过程分为以下任务:

  • 1.构建请求 :此对象负责创建请求以及常见参数,例如HTTP Method ,标HeadersBody以及请求本身的Path
  • 2.执行请求 :这部分负责执行对底层的请求-通常是通过URLSessionAlamofire或任何您想要的东西实现的网络(“通常”,因为该体系结构允许我们甚至创建返回模拟数据的伪层)
  • 3.解析响应 :在这一步中,我们读取原始输出并提供数据的初始表示(或获取收到的错误)。 通常,这是我们检查输出正确性,格式本身并检查HTTP状态代码内直接不可用的任何错误的点(即带有错误详细说明的“ error_message ”键)。
  • 4.执行操作 :这是更高的抽象级别。 在此类中,您将执行一个逻辑运算,并将从底层接收的原始数据转换为应用程序的可用实体(即,从原始JSON转换为“ User”实体)

建立请求

该请求代表一个并且只有一个网络操作。 将其视为我们网络层的原子单元Request的作用是配置HTTP请求的必要参数,至少包括:

  • 请求的path (即/api/v1/loginUser
  • 使用的HTTP Method (即POSTPUT或其他方法)
  • 要附加的headers (即CookiesAuthorization或其他内容)
  • 请求的body (可能是JSON数据,XML,多部分数据等等)

这是使用Swift的两个突出功能的绝好机会: ProtocolsType-Safety

我们的Request对象将是一个简单的protocol ,该protocol定义与网络请求相关的最常见属性:

尽管我知道这不是该主题的最终用语,但我很乐于查看其他解决方案或使以下描述的解决方案变得更好的方法。

我在等你的贡献,让我们谈谈😉

费尔南多·马丁·奥尔蒂斯 FernandoMartínOrtiz )撰写了有关该主题的另一篇文章 :“ 在Swift中隔离任务,或如何创建可测试的网络层