在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
项目名称:HandyJSON 项目地址:https://github.com/alibaba/handyjson 背景JSON是移动端开发常用的应用层数据交换协议。最常见的场景便是,客户端向服务端发起网络请求,服务端返回JSON文本,然后客户端解析这个JSON文本,再把对应数据展现到页面上。 但在编程的时候,处理JSON是一件麻烦事。在不引入任何轮子的情况下,我们通常需要先把JSON转为Dictionary,然后还要记住每个数据对应的Key,用这个Key在Dictionary中取出对应的Value来使用。这个过程我们会犯各种错误:
为了解决这些问题,很多处理JSON的开源库应运而生。在Swift中,这些开源库主要朝着两个方向努力:
对于1,使用最广、评价最好的库非 SwiftyJSON 莫属,它很能代表这个方向的核心。它本质上仍然是根据JSON结构去取值,使用起来顺手、清晰。但也正因如此,这种做法没能妥善解决上述的几个问题,因为Key、路径、类型仍然需要开发者去指定; 对于2,我个人觉得这是更合理的方式。由于Model类的存在,JSON的解析和使用都受到了定义的约束,只要客户端和服务端约定好了这个Model类,客户端定义后,在业务中使用数据时就可以享受到语法检查、属性预览、属性补全等好处,而且一旦数据定义变更,编译器会强制所有用到的地方都改过来才能编译通过,非常安全。这个方向上,开源库们做的工作,主要就是把JSON文本反序列化到Model类上了。这一类JSON库有 ObjectMapper、JSONNeverDie、HandyJSON 等。而 HandyJSON 是其中使用最舒服的一个库,本文将介绍用 HandyJSON 来进行Model和JSON间的互相转换。 为什么用HandyJSON在Swift中把JSON反序列化到Model类,在
这两者都有显而易见的缺点。前者要求Model继承自 而 把JSON转换为Model简单类型某个Model类想支持通过 比如我们和服务端约定了一个 class Animal: HandyJSON { var name: String? var id: String? var num: Int? required init() {} // 如果定义是struct,连init()函数都不用声明; } 然后假设我们从服务端拿到这样一个JSON文本: let jsonString = "{\"name\":\"cat\",\"id\":\"12345\",\"num\":180}"
引入 if let animal = JSONDeserializer<Animal>.deserializeFrom(json: jsonString) { print(animal.name) print(animal.id) print(animal.num) } 简单吧~ 比较复杂的类型
struct Cat: HandyJSON { var id: Int64! var name: String! var friend: [String]? var weight: Double? var alive: Bool = true var color: NSString? } 一样轻松转换: let jsonString = "{\"id\":1234567,\"name\":\"Kitty\",\"friend\":[\"Tom\",\"Jack\",\"Lily\",\"Black\"],\"weight\":15.34,\"alive\":false,\"color\":\"white\"}" if let cat = JSONDeserializer<Cat>.deserializeFrom(json: jsonString) { print(cat.xxx) } 嵌套的Model类如果Model类中的某个属性是另一个自定义的Model类,那么只要那个Model类也实现了 struct Component: HandyJSON { var aInt: Int? var aString: String? } struct Composition: HandyJSON { var aInt: Int? var comp1: Component? var comp2: Component? } let jsonString = "{\"num\":12345,\"comp1\":{\"aInt\":1,\"aString\":\"aaaaa\"},\"comp2\":{\"aInt\":2,\"aString\":\"bbbbb\"}}" if let composition = JSONDeserializer<Composition>.deserializeFrom(json: jsonString) { print(composition) } 指定反序列化JSON中某个节点有时候服务端返回给我们的JSON文本包含了大量的状态信息,和Model无关,比如 struct Cat: HandyJSON { var id: Int64! var name: String! } // 服务端返回了这个JSON,我们想解析的只有data里的cat let jsonString = "{\"code\":200,\"msg\":\"success\",\"data\":{\"cat\":{\"id\":12345,\"name\":\"Kitty\"}}}" // 那么,我们指定解析 "data.cat",通过点来表达路径 if let cat = JSONDeserializer<Cat>.deserializeFrom(json: jsonString, designatedPath: "data.cat") { print(cat.name) } 有继承关系的Model类如果某个Model类继承自另一个 class Animal: HandyJSON { var id: Int? var color: String? required init() {} } class Cat: Animal { var name: String? required init() {} } let jsonString = "{\"id\":12345,\"color\":\"black\",\"name\":\"cat\"}" if let cat = JSONDeserializer<Cat>.deserializeFrom(json: jsonString) { print(cat) }
自定义解析方式
class Cat: HandyJSON { var id: Int64! var name: String! var parent: (String, String)? required init() {} } let jsonString = "{\"cat_id\":12345,\"name\":\"Kitty\",\"parent\":\"Tom/Lily\"}" 可以看到, class Cat: HandyJSON { var id: Int64! var name: String! var parent: (String, String)? required init() {} func mapping(mapper: HelpingMapper) { // 指定 id 字段用 "cat_id" 去解析 mapper.specify(property: &id, name: "cat_id") // 指定 parent 字段用这个方法去解析 mapper.specify(property: &parent) { (rawString) -> (String, String) in let parentNames = rawString.characters.split{$0 == "/"}.map(String.init) return (parentNames[0], parentNames[1]) } } } 就这样, 把Model转换为JSON文本
基本类型如果只需要进行序列化,那么在定义Model类时,不需要做任何特殊的改动。任何一个类的实例,直接调用 class Animal { var name: String? var height: Int? init(name: String, height: Int) { self.name = name self.height = height } } let cat = Animal(name: "cat", height: 30) print(JSONSerializer.serializeToJSON(object: cat)!) print(JSONSerializer.serializeToJSON(object: cat, prettify: true)!) 可以通过 复杂类型即使Model类中有别的Model类啥的,都一样支持。 enum Gender: String { case Male = "male" case Female = "Female" } struct Subject { var id: Int64? var name: String? init(id: Int64, name: String) { self.id = id self.name = name } } class Student { var name: String? var gender: Gender? var subjects: [Subject]? } let student = Student() student.name = "Jack" student.gender = .Female student.subjects = [Subject(id: 1, name: "math"), Subject(id: 2, name: "English"), Subject(id: 3, name: "Philosophy")] print(JSONSerializer.serializeToJSON(object: student)!) print(JSONSerializer.serializeToJSON(object: student, prettify: true)!) 总结有了
|
请发表评论