swift 5.1 Json转换之Codable
对于开发的人员来说,接受后台的数据,并转换成自己的数据模型是常见的事情。但是作为苹果开发者,并没有一个很好的工具去直接转换,必须借助与第三方的开发的库。那么比较好用的有YYModel、MJExtension。当然还有其他的库。但是有个问题,对于第三方库,如果使用过多对于我们开发者来说并不是一件好事。简单分析一下:优点:功能强大,使用方便,提高开发效率,相对较安全出现bug几率较小。缺点:受限于第三方(主要是版本),如果有bug不容易修改,甚至只能官方修改,增大开发包,使用过多容易导致编译速度极慢,实际用到的功能很少。基于以上选择,使不使用第三方自己斟酌,我们这篇文章,在这不做讨论,对于swift而言,我们这篇文章主要讲怎么使用官方的Codable转换成自己的模型。下面进入正题。
swift引入了Codable编码与解码的功能,简单来说就是支持把一个json,转成自己创建并遵从Codable协议的一个数据模型,可以是类,也可以是结构体struct,对于结构体这个是第三方所没有的一个功能。苹果官方推荐使用结构体,方便,安全,占用内存少,还不用担心内存释放问题,好处多多。我们针对struct来说一下。
首先我们先创建一个json数据:
{"name": "张三","age": 20,"birthday": "1990-06","location": "中国","job": "教师"
}
然后我们创建一个结构体模型接收这个数据:
struct UserModel: Codable {var name = "";var age = 0;var birthday = "";var location = "";var job = "";
}
说明这个结构体模型必须实现Codable协议。
然后我们去进行decode解码:
let dict = """
{"name": "张三","age": 20,"birthday": "1990-06","location": "中国","job": "教师"
}
"""
let decode = JSONDecoder();
if let data = dict.data(using: .utf8) {let item = try? decode.decode(UserModel.self, from: data);print("item: \(item)");
}
同过打印我们发现,可以正常输出struct的各个值,使用起来就是这么简单。
2.对于复杂的json我们也是可以解析的。比如下面的json:
{"name": "张三","age": 20,"birthday": "1990-06","location": "中国","job": "教师","students": [{"name": "小丽","age": 12,"id": 1234,"sex": "女"},{"name": "小万","age": 11,"id": 1235,"sex": "男"},{"name": "小明","age": 14,"id": 1237,"sex": "男"}]}
上边这个是比较复杂的,一个对象包括了数组,数组里面又有对象,那么对于这个struct模型我们可以这样创建:
struct UserModel: Codable {var name = "";var age = 0;var birthday = "";var location = "";var job = "";var students: [StudentsModel]!
}struct StudentsModel: Codable {var name = "";var age = 0;var id = 0;var sex = "";
}
使用起来还是上边的那个方法我们可以看到students打印出来的是个数组。
但是有时候,情况并不我们想象中的那么完美,尤其是在命名规则上,后台有可能会出现带下滑杠的命名方式比如:student_name等形式,而swift一般是驼峰是命名比如:studentName,这就带来了一个问题,这两个显示是不匹配的,那么我们怎么解决这个问题呢,比如我们有如下的json数据:
{"name": "张三","phone_number": 18467898765,"pic_url": "中国"
}
这个时候我的需要把手动把属性和值对应起来。
struct UserModel: Codable {var name = "";var phoneNumber = 0;var picURL = "";enum UserKeys: String, CodingKey {case phoneNumber = "phone_number"case picURL = "pic_url"case name = "name"}init(from decoder: Decoder) throws{let value = try? decoder.container(keyedBy: UserKeys.self);phoneNumber = (try? value?.decode(Int.self, forKey: .phoneNumber)) ?? 0;picURL = (try? value?.decode(String.self, forKey: .picURL)) ?? "";name = (try? value?.decode(String.self, forKey: .name)) ?? "";}
}
从上面也可以看出,当键和值的类型不一样的时候我们也是可以转换的。
swift的Codable很简单也很强大,如果我们在实际开发的时候,后台返回来的数据并不是完整的,如果没有那个值可能就不返回来了,这个时候我们上面的问题就暴露出来了。具体是什么错误呢。我们把数据json的name去掉,并改成如下的形式。
数据:{"age": 12,"birthday": "2000-01"
}模型:struct UserModel: Codable {var name = "";var age = 0;var birthday = "";
}
测试方法我们也变一下:
let decode = JSONDecoder();if let data = stringValue.data(using: .utf8) {do {let item = try decode.decode(UserModel.self, from: data);print("item: \(item)");} catch {print("error =\(error)");}}
会打印如下的错误信息:
error =keyNotFound(CodingKeys(stringValue: "name", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"name\", intValue: nil) (\"name\").", underlyingError: nil))
就是我们定义的name是必须有的,但是后台没有返回所以就出错了,这个时候我们要定义成可选类型,如下:
struct UserModel: Codable {var name: String?var age: Int?var birthday: String?
}
这个时候就可以放心的使用了,发现成功答应值,只是name是空。
其实我们发现这些属性的值我们使用过程中一般都是读取,为了更好的表达这个意图,我们一般定义成下面这样,保证了数据的安全:
struct UserModel: Codable {let name: String?let age: Int?let birthday: String?
}
为了更好的使用这个Codable这个特性,我们可以封装一下,给JSONDecoder添加一个扩展,具题如下:
extension JSONDecoder {class func jsonDecoder<T: Codable>(_ type: T.Type,from data: Data?) -> T? {guard let data = data else {return nil;}let json = JSONDecoder();var jsonItem: T? = nil;do {jsonItem = try json.decode(type, from: data)} catch {printObject("data convert json error: \(error)");}return jsonItem;}class func jsonDecoder<T: Codable>(_ type: T.Type,fromAny data: Any?) -> T? {if let data = data as? Data {return jsonDecoder(type, from: data);}guard let data = data else {return nil;}if let stringValue = data as? String {return jsonDecoder(type, from: stringValue.data(using: .utf8));}let jsonData = try? JSONSerialization.data(withJSONObject: data, options: .prettyPrinted);return jsonDecoder(type, from: jsonData);}
}
这样使用起来就方便了许多。好了对于Codable的使用我就说这么多,还有编码也是一样的,可以自己探索一下。
还是那句老话:学习的路上,总不缺少努力的人。祝你越来越
swift 5.1 Json转换之Codable相关推荐
- JSON转换和毫秒时间
JSON转换和毫秒时间 String dataId = "0000000000003000-0001";String baisc= " { "+ " ...
- [转] JSON转换
转载自:http://www.360doc.com/content/12/0413/14/9529755_203286509.shtml# JSON简介 JSON(JavaScript Object ...
- Python JS Jquery Json 转换关系
一.JS对象与JSON格式数据相互转换 目前的项目数据交互几乎都用JQuery,所以处理流程是: 前端页面数据->JS对象->jQuery提交->python处理,另外一种就是倒过来 ...
- json转php数组 在线,PHP如何将JSON转换成数组/对象
在PHP中可以使用json_decode()函数将JSON编码的字符串转换为适当的PHP数据类型.默认情况下,json_decode()函数将返回一个对象:但是,可以指定第二个参数为一个布尔值true ...
- Python-jsonpath使用和json转换
(一)JSONPath-JSON的XPath JSONPath表达式始终以与XPath表达式与XML文档结合使用的相同方式引用JSON结构.由于JSON结构通常是匿名的,并且不一定具有"根成 ...
- 前后台json交互,以及数据库json转换——PHPThinkphp5.1
0. 前言 最近在做一个项目,一个考试系统.后台采用的核心技术是PHP+Thinkhp5.1+Mysql. 要求前后台之间用json数据交互,后台需要将前台json关键字段接收,然后查询数据库,返回相 ...
- 关于json 转换BigDecimal精度丢失问题
今天在转换一个关于金额字段发现一个关于json转换的bug 目前尚未深入观察 问题: 如果金钱为bigdecimal json转换后不会丢失精度 但是通过@responsebody 返回到前端后发现 ...
- javabean与json转换(fastjson与jackson两个版本)
[README] 本文演示了 javabean与json转换的开发方式: 要想 javabean的属性名 与 json的字段名不一致,也是可以转换的: 之前需要引入 ali.fastjson < ...
- python字典与json转换_python字典与json转换的方法总结
在python中json分别由列表和字典组成,本文主要介绍python中字典与json相互转换的方法.使用json.dumps可以把字典转成json字符串.使用json.loads可以把json字符串 ...
最新文章
- CCNA(Stand-ALONE)Lab 12-Static Routes
- 深度学习100例-卷积神经网络(CNN)识别神奇宝贝小智一伙 | 第16天
- hibernate 多对一外键注解
- 三星Galaxy S21+真机上手视频曝光:外观彻底无悬念
- android升序降序按钮,创建一个按钮,将排序MYSQL查询升序和降序
- java字符串数字统计_对字符串进行简单的字符数字统计 探索java中的List功能
- mysql lru scan depth_如何解决mysql警告:“ InnoDB:page_cleaner:1000毫秒的预期循环用了XXX毫秒。设置可能不是最佳的”?...
- 20.23 20.4 20.5告警系统邮件引擎(上中下);20.26 运行告警系统
- MySQL的LIKE模糊查询优化
- BZOJ2748[HAOI2012] 音量调节
- java mschart_vb之mschart控件小结
- 机器视觉入门知识总结
- 微信小程序开发者工具平台+Hbuilder开发平台下载
- Spy++ —— 窗口、消息查看分析利器
- 万网域名证书如何查询下载_备案域名证书获取
- vue3+element plus下面,自定义el-table表格标题
- Java如何设置word中某段文字的字体/段落样式
- 网易5天python编程课_网易云课堂上自学编程?
- 汇编语言实现 大小写字母转换
- cuda和GPU驱动的关系