Swift JSON反序列化Model HandyJSON
2017-11-01 本文已影响43人
EvanJq
在Swift中把JSON反序列化到Model类,在HandyJSON出现以前,主要使用两种方式:
1. 让Model类继承自NSObject,然后class_copyPropertyList()方法获取属性名作为Key,从JSON中取得Value,再通过Objective-C runtime支持的KVC机制为类属性赋值;如JSONNeverDie;
2. 支持纯Swift类,但要求开发者实现Mapping函数,使用重载的运算符进行赋值,如ObjectMapper;
这两者都有显而易见的缺点。前者要求Model继承自NSObject,非常不优雅,且直接否定了用struct来定义Model的方式;后者的Mapping函数要求开发者自定义,在其中指明每个属性对应的JSON字段名,代码侵入大,且仍然容易发生拼写错误、维护困难等问题。
而HandyJSON独辟蹊径,采用Swift反射+内存赋值的方式来构造Model实例,规避了上述两个方案遇到的问题。
要支持从JSON串反序列化,Model定义时要声明服从HandyJSON协议。确实是一个协议,而不是继承自NSObject。
服从HandyJSON协议,需要实现一个空的init方法。
基本操作用例
import UIKit
import HandyJSON
class Model: HandyJSON {
var id = ""
var age = 0
var name = ""
var parent: (String, String)?
var friendName: String?
var notHandyJSONTypeProperty: String?
required init() {}
func mapping(mapper: HelpingMapper) {
// 指定自定义解析规则
mapper <<<
self.id <-- "ID"
mapper <<<
self.parent <-- TransformOf<(String, String), String>(fromJSON: { (rawString) -> (String, String)? in
if let parentNames = rawString?.characters.split(separator: "/").map(String.init) {
return (parentNames[0], parentNames[1])
}
return nil
}, toJSON: { (tuple) -> String? in
if let _tuple = tuple {
return "\(_tuple.0)/\(_tuple.1)"
}
return nil
})
// 指定一个属性的解析路径
mapper <<<
self.friendName <-- "friend.name"
// 排除指定属性
mapper >>> self.notHandyJSONTypeProperty
}
// 解析成功后回调
func didFinishMapping() {
print("you can fill some observing logic here")
}
}
let dic: [String : Any] = ["name": "小明", "age": 1, "parent": "Dad/Mom", "friend": ["name": "小王"]]
if let model = Model.deserialize(from: dic) {
print("name: \(model.name) age: \(model.age) parent: \(model.parent) friendName: \(model.friendName)")
}
注意:HandyJSON是直接在内存中完成赋值的,绕过了一些观察函数,导致didSet/willSet不生效。你需要手动地在序列化前后调用你自己需要处理的逻辑。但在1.8.0版本之后,HandyJSON对dynamic类型的属性使用KVC机制处理,会触发KVO机制。所以如果你真的需要 willSet/didSet,可以将类型声明为dynamic。
这里只做简单介绍,如需详细学习参见HandyJSON。