使用面向协议的编程进行通用JSON解析


澄清
Codable,本文是关于实现可与Codable或您可能选择的任何东西一起使用的体系结构的


每个(Swift)软件开发人员最终都将需要为其iOS应用程序(或macOS)解析JSON。

在我的整个职业生涯中,我已经看到了许多关于如何解析JSON的体系结构方法。

您应该经常问自己(开发的任何功能):

  • 您构建的体系结构是否是一种演化系统,可以在不修改基础代码/类/结构的情况下适应任何给定的更改 如果不是,则不敏捷
  • 如果您的方法基于OOP,您是否保持SOLID原则不变?
  • 服务是否为松耦合?

在最近的一次聚会中,我也参加了有关体系结构方法和原理的会议,他们展示了一张带有引号的幻灯片:

开发人员知道可以做什么。
应该做的。

那么应该怎么做……?


让我们分解一下JSON解析,即解析JSON涉及的内容:

  1. 调用一个请求到服务器并从闭包中获得响应 (例如)。
  2. 在大多数项目中,服务器端以不同的合法性响应我们的请求,因此,我们需要一个验证器来验证JSON响应的合法性,而不管我们需要解析的实际数据如何。
    4xx我们可以验证JSON,否则,我们将返回错误。
  3. 解析 JSON并反序列化相关对象
  4. 验证器 返回相关错误

没什么新鲜的,简单明了的🙂


我们的主要目标是编写一个小型且集中的代码,以分离上述所有步骤,并且当然要使用POP方式 面向协议的编程 )。

我是Alamofire的忠实拥护者,因此我们假设响应是标准的DataResponse

  Alamofire.request(...)。responseJSON {(resp:DataResponse )in ...} 

我们需要一个协议,该协议将描述我们先前细分的方法集。 我们将需要3种方法:

  1. 封装运行整个“显示”的实际逻辑的方法。
  2. 验证JSON的方法-此方法将返回内部JSON(稍后将显示一个示例)。
  3. 一种将解析我们的数据并创建实际对象的方法,该对象应该位于内部JSON内部。
 公共协议ParseProtocol { 

)-> 吗?
扩展ParseProtocol {

}

那返回类型呢?

由于方法begin将封装“整个”逻辑,因此它应该返回我们解析的对象以及一个Error类型,然后返回一个元组如何:

  func begin(forResponse响应:DataResponse )->(值:任何?,错误:错误?) 

此时,我们将使用返回的已解析对象的类型作为Any。

如果您已经注意到需要正确的关联类型,那么我们稍后会处理此功能

如果begin将返回上述元组,则显然parseData将返回完全相同的元组,因为begin是入口点, parseData是出口点,因此,我们将定义类型别名:

  typealias ReturnedValueErrorTuple =(值:任何?,错误:错误?) 

还有两个要解析的类型, parseData签名参数和validateData返回的类型。 如前所述, validateData将通过检查代表服务器响应的自定义特定键来解析JSON,例如:

{ 
"data": {
}

在此示例中,我们将要检查状态键值是什么,如果为true,则将从数据键中解析JSON,从而为内部JSON做好了准备,可以将其解析为具体对象,因此,它可以将任何内容从Dictionary类型返回到Array类型,因此就目前而言, Any将是一个不错的选择。

如果状态值为false怎么办? 我们将要提取错误消息以显示给用户,例如:

 { 
"statusText": "The machines are digging and your data is doomed"

因此,除了表示内部JSON的Any类型之外,我们还需要返回一个Error类型,该类型将表示事情被搞砸的原因。 听起来像另一个元组将由另一个类型别名表示:

  typealias ValueErrorTuple =(值:任何?,错误:错误?) 

那些具有快速感知能力的人已经注意到,如果内部JSON这样表示为Any类型,则parseData签名参数也应该为Any。

注意:validateData返回类型为Any的对象,因此parseData应该接收它

最后,我们的新协议:

注意新添加的内容: 协议名称的后缀; 具有ParseProtocol解析能力的这是因为它具有新的实现:

我们将创建一个保存数组的数据控制器结构和一个调用AWESOME fetchFeedObjects方法的方法。 最重要的是,我们现在将Parseable对象( FeedArrayParser )的实例注入到method参数中:

现在,为了使用关于validateData的不同逻辑创建不同的Parseable对象,我们将简单地实现Parseable并使用我们的关联类型编写我们自己的validateData方法,例如:Facebook或其他服务器请求。

对于那些喜欢UML方式的人:

  • 通过实现可解析协议
  • 创建约束类型为异步方法
  • 别忘了最后所有异步方法会导致启动request方法的相同requestParseableData。
  • 我们可以将具体的Parseable实例注入异步方法

这种基于POP的体系结构确实功能强大 ,最重要的是,功能强大

解析JSON的方式有很多种,我在这里并不是要告诉您POP方式是最好的选择,但它当然也是我们应该注意的有力选择。


如果您有任何疑问/评论/启示或任何相关的内容,我很乐意在 Twitter上 或什至在评论部分 与您讨论