JSON 自动生成HandyJson Model Class

1,557

本文衔接 如何将JavaScript转化成Swift?(二) ,主要是关于将JavaScript的解析Json代码翻译到Swift当中?(如何将一段Json字符串自动生成HandyJson格式的Model类)

将JavaScript的解析JSON代码翻译到Swift

JSON解析

{
    "error":0,
    "msg":"success",
    "data":[
        {
            "id":27,
            "name":"协议和帮助",
            "sname":"xy",
            "parent_id":"0",
            "flag":"0",
            "created":"2017-01-15 09:47:09",
            "tag":[
                1,
                5
            ],
            "dated":"2017-01-15 16:31:32"
        }
    ]
}

JavaScript 解析Json

JavaScript 中获取 "name" 只需要一行代码即可

var jsonObj = str.parseJSON();
jsonObj.data[0].name

Swift 解析 Json

Swift中常用的JOSN解析库有 HandyJson、ObjectMapper、SwiftyJson

SwiftyJson 不要预先定义 Model Class 文件,但是不支持转Mode,而且解析Json的语法和Js差异较大;

ObjectMapper Model类必须实现Mappable协议,即实现init和mapping函数;适合跟Alamofire配合。但是mapping函数过于臃肿耗时;

HandyJson 采用Swift反射+内存赋值的方式来构造Model实例,写法简便且能支持json和model互转的需求,而且一直在更新维护,解析Json的语法和Js差异较小;

结论: 采用HandyJson来进行Json解析!

如何生成HandyJson所需要的Model类?

这里就直接贴代码了。。。


// 生成Swift的Model文件
var generateCode = function (jsonString, className) {
    var k = "";

    // 首字母大写
    var toUpperVar = function (a) {
        return a.replace(/\b[a-z]/g, function (a) {
            return a.toUpperCase()
        })
    };

    // 小写
    var toLowerVar = function (a) {
        return a.replace(/\b[a-z]/g, function (a) {
            return a.toLowerCase()
        })
    };

    // 判断是否有嵌套的Model
    var q = function (a) {
        // 判断是否是一个数组
        return a instanceof Object ? a.constructor.prototype.hasOwnProperty("push") : !1
    };

    var r = function (a) {
        // 判断是否是一个数组
        return a instanceof Object ? !a.constructor.prototype.hasOwnProperty("push") : !1
    };

    // 生成 class
    var getClass = function (a, d) {
        let required = "\n    required init() {}"
        return "class " + a + ": HandyJSON {\n" + d + required + "\n}"
    };

    // 生成变量
    var getVar = function (a, d) {
        return "    var " + d + ": " + a + "\n"
    };

    // swift  解析 json
    var generateSwift = function (a, d) {
        var c = "";
        if (q(a)) {
            if (a.length > 0) {
                for (var e = a[0], f = a.length - 1; 0 <= f; f--) {
                    var b = a[f];
                    q(b) ? b.length > e.length && (e = b) :
                        r(b) && Object.keys(b).length > Object.keys(e).length && (e = b)
                }
                c += generateSwift(e, d)
            }
        } else if (r(a)) for (e in a) {
            b = a[e];
            var h = toUpperVar(e);
            f = toLowerVar(e);
            if (q(b)) {
                var g;
                // 获取第一个
                0 < b.length && (g = b[0]);

                if ("string" === typeof g) {
                    c += getVar("[String]!", f);
                } else {
                    if ("number" === typeof g) {
                        // 判断浮点数
                        if (0 <= b.toString().indexOf(".")) {
                            c += getVar("[Float]!", f);
                        } else {
                            c += getVar("[Int]!", f);
                        }
                    } else if ("boolean" === typeof g) {
                        c += getVar("[Bool]", f)
                    } else if ("object" === typeof g) {
                        h += "Item";
                        c += getVar("[" + h + "]!", f);
                        b = generateSwift(b, e);
                        if (0 < k.length) {
                            k += "\r\n\r\n" + getClass(h, b)
                        } else {
                            k = getClass(h, b)
                        }
                    }
                }
            } else {
                if (r(b)) {
                    b = generateSwift(b, e)
                    c += getVar(h, f)
                    k = 0 < k.length ? k + "\r\n\r\n" + getClass(h, b) : getClass(h, b)
                } else {
                    if ("string" === typeof b) {
                        c += getVar("String = ''", f)
                    } else if ("number" === typeof b) {
                        // 判断浮点数
                        if (0 <= b.toString().indexOf(".")) {
                            c += getVar("Float = 0.0", f)
                        } else {
                            c += getVar("Int = 0", f)
                        }
                    } else if ("boolean" === typeof b) {
                        c += getVar("Bool = false", f)
                    }
                }
            }
        } else alert("key = " + d); return c
    };

    var swiftFunc = function (a, d) {
        k = ""
        0 == d.length && (d = "DefaultModelName");
        var c = generateSwift(a, d);
        k = 0 < k.length ? k + "\r\n\r\n" + getClass(d, c) : getClass(d, c);
        return k
    };

    return {
        swiftModel: function () {
            var d = eval("(" + jsonString + ")");
            return swiftFunc(d, toUpperVar(className))
        }
    }

};

exports.generateCode = generateCode;

如何调用?

var generateModel = require('./generateModel.js');
var fs = require("fs")
const { exec } = require('child_process');

var d = "{'error': 0,'msg': 'success','data': [{'id': 27,'name': '协议和帮助','sname': 'xy','parent_id': '0','flag': '0','created': '2017-01-15 09:47:09','tag':[1, 5], 'dated': '2017-01-15 16:31:32'}]}"

var fileName = "testModel"
var code = generateModel.generateCode(d, fileName).swiftModel();
console.log(code)


fs.writeFile('./Swift_Code/' + fileName + '.swift', code,  function(err) {
    if (err) {
        return console.error(err);
    }
 });
 
 // 格式化代码
 exec('swiftformat ./Swift_Code/' + fileName + '.swift --swiftversion 4.2 ', (err, stdout, stderr) => {
     if(err) {
         return;
     }
 })
 

执行上述代码即可生成如下文件:

class DataItem: HandyJSON {
    var id: Int = 0
    var name: String = ""
    var sname: String = ""
    var parent_id: String = ""
    var flag: String = ""
    var created: String = ""
    var tag: [Int]!
    var dated: String = ""

    required init() {}
}

class TestModel: HandyJSON {
    var error: Int = 0
    var msg: String = ""
    var data: [DataItem]!

    required init() {}
}

这里为了避免Optional解析发生Crash,所以都赋了一个默认值,总感觉会有一点问题,后面再修改。。。

将JavaScript解析Json代码翻译成Swift

完成了Model的生成,将JavaScript的解析Json代码解析翻译成Swift就简单很多了

jsonObj.data[0].name 甚至可以不用修改直接翻译即可 ~

最后贴上生成HandyJson的 代码

如何将JavaScript转化成Swift?(一)

如何将JavaScript转化成Swift?(二)