JSON

Swift 解析 Json 的方式足以让任何代码段看起来就像一坨米田共……这不是在开玩笑,因为你真的是一层一层堆上去的。

好在,程序员总是有办法实现自己的优雅。JSONModel, YYModel 等类库都是非常好用的 Json 解析库。可以直接把 Json 数据解析成对象。这样就可以在工作中非常好的使用了。

Swift 在这方面有先天的不足,因为所有的这些实现都离不开 KeyValue 的使用。但是说实话,非必要情况下,我是真不愿让我的模型继承自 NSObject. 毕竟那是非常 OC 的东西。再加上我有一个非常让人烦躁的工作环境,写服务器的人三天两头的变更数据结构。而且它还很喜欢对象套对象,这就让使用这些库的安卓同事很无奈了。这意味着他要经常新增对象,修改属性名称。

在偶然的情况下,我看到一个对于 Json 解析的类库,并不是把它解析成模型,而是通过下标的方式直接读取 Json 内容。如:

var some = json["value", "some"].string

很遗憾的是当时我没有把这个类库给 Git 下来,但是其实想想,这样的实现可以非常的简单。于是,我又造了个轮子。

背景知识

JSONSerialization

  • 将 Json 数据转换成字典
JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)
  • 将字典转换成 Json
/// 这段代码是在 Swift 2 的环境下截取的,我稍微做了点修改,让他看起来更像 Swift 3... 总之,有时间改一下吧。
JSONSerialization.data(json, options: NSJSONWritingOptions.PrettyPrinted)

Subscrpts 下标

下标的语法很简单,是 Swift 当中非常华丽的功能。

subscript(index: Int) -> Int {
    get {
        // return an appropriate subscript value here
    }
    set(newValue) {
        // perform a suitable setting action here
    }
}

Apple: The Swift Programming Language (Swift 3) -> Language Guide -> Subscrpts

思考

首先假设我们清晰的知道完整的 Json 数据结构。这应该是必要的条件。

{
    value: {
        int: {
            10,
            20,
            30
        },
        string: "Some String",
        date: "2016-09-30"
    }
}

那么,最终我希望能拿到数据应该是类似

json["value", "int", 1].int

json 为数据对象,[] 下标当中放置的是完整的读取路径,表示 value 字段下的 int 字段里的第一个元素。后面表示将它读成 int 类型。

所以关键点就是

  • 数据存储
  • 解析链条
  • 类型指定

另外需要考虑两个错误情况

  • 链条错误,字段并不存在
  • 类型错误

解决方法其实很简单,假如链条错误,那就返回 nil 即可。类型错误可以考虑两种情况,一种是即使错误也能读取一个默认值,一种是读取错误返回 nil。(至少我是不希望读取错误就直接把程序中断了,谁知道会不会在程序上线后服务器改了一个字段大小写呢……又不是没遇到过。)

因此对于直接指定类型的如 int, string 这种返回的应该是 option 类型。并提供一个方法,可以指定类型的同时指定默认值,如果类型错误就返回默认值。

实现代码如下,只要用泛型即可解决。会自动根据所给的 null 参数判断所需要的类型,然后进行类型判断。

    func type<T>(null: T) -> T {
        if let v = result as? T {
            result = json
            return v
        } else {
            result = json
            return null
        }
    }

实现

这么简单的类,这个类其实早已经实现好,并拿我自己的项目做过小白鼠了,所以我就不写伪代码了。

//
//  Json.swift
//  Json
//
//  Created by 黄穆斌 on 16/9/25.
//  Copyright © 2016年 MuBinHuang. All rights reserved.
//

import Foundation

// MARK: - Json Data

class Json {

    // MARK: Tmp Data

    var json: Any? { didSet { result = json } }
    var result: Any?

    // MARK: Init

    init(_ data: Data?) {
        if let data = data {
            if let json = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) {
                self.json = json
                self.result = json
            }
        }
    }

    init(_ json: Any) {
        self.json = json
        self.result = json
    }

    // MARK: Subscript

    subscript(keys: Any...) -> Json {
        var tmp: Any? = result
        for (i, key) in keys.enumerated() {
            if i == keys.count - 1 {
                if let data = tmp as? [String: Any], let v = key as? String {
                    result = data[v]
                    continue
                } else if let data = tmp as? [Any], let v = key as? Int {
                    if v < data.count {
                        result = data[v]
                        continue
                    }
                }
            } else {
                if let data = tmp as? [String: Any], let v = key as? String {
                    tmp = data[v]
                    continue
                } else if let data = tmp as? [Any], let v = key as? Int {
                    if v < data.count {
                        tmp = data[v]
                        continue
                    }
                }
            }
            tmp = nil
        }
        return self
    }

    // MARK: Types

    var int: Int? {
        let value = result as? Int
        result = json
        return value
    }

    var double: Double? {
        let value = result as? Double
        result = json
        return value
    }

    var string: String? {
        let value = result as? String
        result = json
        return value
    }

    var date: Date? {
        if let value = result as? Double {
            result = json
            return Date(timeIntervalSince1970: value)
        } else {
            result = json
            return nil
        }
    }

    var array: [Json] {
        if let value = result as? [AnyObject] {
            result = json
            var arr = [Json]()
            for v in value {
                arr.append(Json(v))
            }
            return arr
        }
        result = json
        return []
    }

    var dictionary: [String: Json] {
        if var value = result as? [String: AnyObject] {
            result = json
            for (k, v) in value {
                value[k] = Json(v)
            }
            return value as! [String: Json]
        }
        result = json
        return [:]
    }

    func type<T>(null: T) -> T {
        if let v = result as? T {
            result = json
            return v
        } else {
            result = json
            return null
        }
    }

    func date(_ format: String) -> String {
        if let value = result as? Double {
            result = json
            let form = DateFormatter()
            form.dateFormat = format
            return form.string(from: Date(timeIntervalSince1970: value))
        } else {
            result = json
            return ""
        }
    }

    // MARK: Methods

    func value(key: String, _ null: String = "") -> String {
        if let dic = result as? [String: Any] {
            if let value = dic[key] as? String {
                result = json
                return value
            }
        }
        result = json
        return null
    }

    func value<T>(key: String, _ null: T) -> T {
        if let dic = json as? [String: Any] {
            if let value = dic[key] as? T {
                result = json
                return value
            }
        }
        result = json
        return null
    }
}

// MARK: - Json Protocol

protocol JsonProtocol {

    func jsonToModel(json: Json)

}

总结

在类的最后,我写了一个协议,定义了一个 jsonToModel 的方法。事实上,这个协议并没有什么意义,关键是要提供我自己,在我写的模型中,需要加入这个协议,然后在里面实现 json 数据与类属性之间的对应关系。这一块代码,实际上应该是属于模型自己本身做的事情。不应该把这个解析过程放在网络实现当中。

  • 网络类:负责网络传输。
  • 模型类:负责数据处理。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值