使用面向协议的编程进行通用JSON解析
澄清 :
Codable,本文是关于实现可与Codable或您可能选择的任何东西一起使用的体系结构的
每个(Swift)软件开发人员最终都将需要为其iOS应用程序(或macOS)解析JSON。
在我的整个职业生涯中,我已经看到了许多关于如何解析JSON的体系结构方法。
您应该经常问自己(开发的任何功能):
- 您构建的体系结构是否是一种演化系统,可以在不修改基础代码/类/结构的情况下适应任何给定的更改( 如果不是,则不敏捷 ) 。
- 如果您的方法基于OOP,您是否保持SOLID原则不变?
- 服务是否为松耦合?
在最近的一次聚会中,我也参加了有关体系结构方法和原理的会议,他们展示了一张带有引号的幻灯片:
开发人员知道可以做什么。
应该做的。
那么应该怎么做……?
让我们分解一下JSON解析,即解析JSON涉及的内容:
- 调用一个请求到服务器并从闭包中获得响应 (例如)。
- 在大多数项目中,服务器端以不同的合法性响应我们的请求,因此,我们需要一个验证器来验证JSON响应的合法性,而不管我们需要解析的实际数据如何。
4xx我们可以验证JSON,否则,我们将返回错误。 - 解析 JSON并反序列化相关对象
- 从验证器 返回相关错误 。
没什么新鲜的,简单明了的🙂
我们的主要目标是编写一个小型且集中的代码,以分离上述所有步骤,并且当然要使用POP方式( 面向协议的编程 )。
我是Alamofire的忠实拥护者,因此我们假设响应是标准的DataResponse :
Alamofire.request(...)。responseJSON {(resp:DataResponse )in ...}
我们需要一个协议,该协议将描述我们先前细分的方法集。 我们将需要3种方法:
- 封装运行整个“显示”的实际逻辑的方法。
- 验证JSON的方法-此方法将返回内部JSON(稍后将显示一个示例)。
- 一种将解析我们的数据并创建实际对象的方法,该对象应该位于内部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上 或什至在评论部分 与您讨论 。