Json转模型1--SwiftyJson

JSON是移动端开发常用的应用层数据交换协议。最常见的场景便是,客户端向服务端发起网络请求,服务端返回JSON文本,然后客户端解析这个JSON文本,再把对应数据展现到页面上。
但在编程的时候,处理JSON是一件麻烦事。在不引入任何轮子的情况下,我们通常需要先把JSON转为Dictionary,然后还要记住每个数据对应的Key,用这个Key在Dictionary中取出对应的Value来使用。这个过程我们会犯各种错误:

* Key拼写错了
* 路径写错了
* 类型搞错了
* 没拿到值懵逼了
* 某一天和服务端约定的某个字段变更了,没能更新所有用到它的地方
* ...

为了解决这些问题,很多处理JSON的开源库应运而生。在Swift中,这些开源库主要朝着两个方向努力:

1. 保持JSON语义,直接解析JSON,但通过封装使调用方式更优雅、更安全
2. 预定义Model类,将JSON反序列化为类实例,再使用这些实例

对于1,使用最广、评价最好的库非 SwiftyJSON 莫属,它很能代表这个方向的核心。它本质上仍然是根据JSON结构去取值,使用起来顺手、清晰。但也正因如此,这种做法没能妥善解决上述的几个问题,因为Key、路径、类型仍然需要开发者去指定;

对于2,我个人觉得这是更合理的方式。由于Model类的存在,JSON的解析和使用都受到了定义的约束,只要客户端和服务端约定好了这个Model类,客户端定义后,在业务中使用数据时就可以享受到语法检查、属性预览、属性补全等好处,而且一旦数据定义变更,编译器会强制所有用到的地方都改过来才能编译通过,非常安全。这个方向上,开源库们做的工作,主要就是把JSON文本反序列化到Model类上了。这一类JSON库有 ObjectMapper、JSONNeverDie、HandyJSON 等。

今天我们先来看看SwiftyJSON的用法。

通常我们拿到数据会进行非常麻烦的optinonal(可选类型)进行拆包(Wrapping )操作,
SwiftyJson内部会自动对optional进行拆包,大大简化了代码,解析非常方便,拿到的json数据data直接扔进去

//转成JSON对象
let jsonData = JSON.init(data)

不管需要什么数据只要通过对jsonData进行路径读取
例如:

let build_name = jsonData[0]["build_name"].stringValue

值得一提的是,不需要考虑服务器给我们返回的是什么类型,比如去请求一个房屋的栋数"build_num": 588我们想要获得Int类型或者String类型都可以

let room_num1 = jsonData[0]["build_num"].stringValue
let room_num2 = jsonData[0]["build_num"].intValue
// room_num1 = 588   String类型
// room_num2 = 588   Int类型

这样通过.stringValue .intValue 就可以获得不可选值类型,如果没有获取到数据的话就会返回一个默认值即.stringValue获得空字符串"".intValue得到0.arrayValue获得空数组[],我们就不用判断拆包了。

当然某些场景可能需要你得到可选值类型并自己判断是否存在,那么我们可以通过.string .int .bool .float .array .dictionary等等方法获取,例如:

//String
if let build_name = jsonData[0]["build_name"].string {
    print(build_name)
} else {
    //打印错误信息
    print(jsonData[0]["build_name"])
}

解析数据是真的非常简单。详细使用可以看看SwiftyJSON的使用详解(附样例)
或者移步GitHub-SwiftyJson
但是对于项目而言我们需要对数据进行转换为模型,仅仅是对data进行JSON读取是远远不够的,想想,如果遇到许多地方都用到了build_name值,但是当服务器给我们返回的字段名字改了,我们改项目时就会显得麻烦,甚至造成改不完全,所以我们队数据封装一下转为模型,这样修改时只用改一个地方就是model的赋值就好了。

那我的方法是:

//这是模拟数据
let baseInfo: [String : Any] = ["build_name":"置信·原墅",
                                  "build_address":"学院中路与金桥路交汇处东北侧",
                                  "build_num": 12,
                                  "room_num": 588,
                                  "area_address":"浙江省温州市鹿城区五马街道"]

创建struct模型,当然Class也可以,但是如果不需要继承也不复杂推荐struct(-。-不多解释了)
并写好创建方法

import SwiftyJSON

struct BuildBaseInfoModel {
    var build_name: String?
    var build_address: String?
    var build_num: String?
    var room_num: String?
    var area_address: String?
    
    init(jsonData: JSON) {
        build_name    = jsonData["build_name"].stringValue
        build_address = jsonData["build_address"].stringValue
        area_address  = jsonData["area_address"].stringValue
        room_num      = jsonData["room_num"].stringValue
        build_num     = jsonData["build_num"].stringValue
    }
}

调用:

let jsonData = JSON(baseInfo)
let model = BuildBaseInfoModel.init(jsonData: jsonData)
// 会得到创建好的 BuildBaseInfoModel类型的 对象model
// 也可以这样写
let model = BuildBaseInfoModel(jsonData: jsonData)

当然这只是普通的模型,经常会遇到复杂模型,例如:

// 面积中89是Int, 109和129是String
let baseInfo: [String : Any] = ["build_name":"置信·原墅",
                                  "build_address":"学院中路与金桥路交汇处东北侧",
                                  "area_address":"浙江省温州市鹿城区五马街道",
                                  "area":[89,"109","129"],
                                  "detail_address":["province":"浙江省",
                                                    "city":"温州市",
                                                    "district":"鹿城区",
                                                    "street":"五马街道"],
                                  "build_num": 12,
                                  "room_num": 588]

这时候模型就应该有两个

struct BuildBaseInfoModel {
    
    var build_name: String?
    var build_address: String?
    var build_num: String?
    var room_num: String?
    var area_address: String?
    var detail_address: DetailAddressModel
    var area:[Any]?
    // 这里面积area中就不能再用arrayValue获取了,因为arrayValue获取的为JSON类型,我们需要转为我们需要的对象
    init(jsonData: JSON) {
        build_name    = jsonData["build_name"].stringValue
        build_address = jsonData["build_address"].stringValue
        area_address  = jsonData["area_address"].stringValue
        room_num      = jsonData["room_num"].stringValue
        build_num     = jsonData["build_num"].stringValue
        area          = jsonData["area"].arrayObject
        detail_address = DetailAddressModel(jsonData: jsonData["detail_address"])
    }
}
struct DetailAddressModel {
    var province: String?
    var city: String?
    var district: String?
    var street: String?
    
    init(jsonData: JSON) {
        province = jsonData["province"].stringValue
        city = jsonData["city"].stringValue
        district = jsonData["district"].stringValue
        street = jsonData["street"].stringValue
    }
    
}
let model = BuildBaseInfoModel(jsonData: jsonData)
DPrint(message: model.detail_address.city)
DPrint(message: model.area?.first)
DPrint(message: model.area?[1])
// xxxxxxxxx.swift[21], updateRoomsData(index:): Optional("温州市")
// xxxxxxxxx.swift[22], updateRoomsData(index:): Optional(89)
// xxxxxxxxx.swift[22], updateRoomsData(index:): Optional("109")

好了,完成,虽然解析Json数据非常方便,但是创建模型的时候,还是略显繁琐。不过不管怎么说目的达到了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容

  • //我所经历的大数据平台发展史(三):互联网时代 • 上篇http://www.infoq.com/cn/arti...
    葡萄喃喃呓语阅读 51,170评论 10 200
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,975评论 4 60
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,559评论 18 139
  • 这个连接讲的很好,一下实例整合至该链接参考来源 1,一个简单的form表单 效果 2, 这是一个包含较多表单元素的...
    夜月行者阅读 1,278评论 0 0
  • 还没忙完,抽空写几个字。 早起练功,忘记练的啥了。带上公子骑行,顺便买菜,一个半小时,让他体会一下妈妈的生活,他说...
    周湘泉阅读 154评论 1 3