iOS收藏

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

上一篇下一篇

猜你喜欢

热点阅读