[Swift] 从 JSON 到 Model: 协议默认方法让生活更简单

2016-12-25 14:51:28 +08:00
 banxi1988

背景

之前介绍的模型字段生成代码中, 我们默认生成了 init(json:JSON) 方法. 假设就是如下的 User Model

struct User{
  let name:String
  let age:Int
  init(json: JSON) {
    self.name = json["name"].stringValue
    self.age = json["age"].intValue
  }
}

开发中我们经常需要得到的是 一个 User 数组.

完善之路

  1. 也许我们会写如下的方法:
func parseUsers(from data:JSON) -> [User]{
  var array:[User] = []
  for (index,json) in data{
  		array.append(User(json:json))
  }
  return array
}
  1. 上面的代码,对于 Swift 来说, 还有很大的改进空间. 首先. 我们可以简化成一行代码, 如下:
func parseUsers(from data:JSON) -> [User]{
  return data.map{ User(json:$0.1) }
}

够简单了吧. 使用 map 方法. 一行就 OK 了. 简单明了. 但是

终极简化

在 Swift 中我们可以一行代码都不写.就实现上面的功能. 怎么实现? 答案就在神奇的默认协议实现方法上.

  1. 我们对 Model 类提取一个协议出来 如下: 很简单,就是指定模型类可以从 JSON 反序列化成 Model.
public protocol JSONDeserializable {
  init(json:JSON)
}
  1. 声明 User 实现了 上面的协议.
extension User:JSONDeserializable{ 
}

因为我们实际上已经实现了. 所以我们不要额外写代码了.

  1. JSONDeserializable 添加一个默认协议静态方法. 用来将 JSON 数组转换成 Model 数组. 如下.
extension JSONDeserializable{
  public static func objects(from json: JSON) -> [Self]{
    return json.map{ Self(json:$0.1) }
  }
}

OK 大功告成!. 现在反序列化一个 User 数组的 json 只需要这样写就可以了.

  let users = User.objects(from: json)

更重要 的是,所以其他的 Model 类型,只要添加实现 JSONDeserializable 的声明就拥有了从 JSON 数组反序列化的能力了.

总结

至此,整个从 API 到 Model 的流程都变得无比简单,及别人愉快.

  1. 使用 generate_model 服务将 从 API 的 JSON 返回转化成 Model 的声明. (生成的代码中的 BXModel 协议,继承声明了 JSONDeserializable)

  2. 借助 Swift 默认协议. 简化 Model 数组的反序列化.

开源:从 API 到 Model 的代码生成脚本

5015 次点击
所在节点    iDev
4 条回复
janita
2016-12-25 23:21:28 +08:00
用在什么地方呢?
banxi1988
2016-12-26 08:50:20 +08:00
@janita 用在你的 Model 上.
Tangdixi
2017-01-09 23:40:36 +08:00
POP 大法好
HHHH
2017-11-27 17:11:09 +08:00
py 大法好~~

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/330014

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX