在本章中,你将学会如何引用并解析JSON
数据。
JSON
,是JavaScript
对象表示法的简称,是客户机和服务器应用程序中用于数据交换的一种常见数据格式。我们App客户端发送网络请求,服务端就会返回JSON
文本,供App
客户端进行解析,解析完成后客户端再把对应数据展现到页面上。
我们学习下JSON
数据及其解码方式的相关内容。
项目创建
首先,创建一个新的Playground
文件,命名为SwiftUIJSON
。
变量声明
我们创建一个简单的json
数据。
let json = """
{
"name": "Ricardo",
"country": "China",
"city": "Guangzhou"
}
"""
然后,我们定义下需要的参数名称,我们需要新建一个personalInformation
个人信息的结构体来定义json
数据里的参数。
struct personalInformation: Codable {
var name: String
var country: String
var city: String
}
这里,我们使用的personalInformation
个人信息结构体需要遵循Codable
可编码协议,并且personalInformation
个人信息结构体中定义的变量需要与JSON
的键一一匹配。
实例化
接下来,我们解析下json
数据。
let decoder = JSONDecoder()
if let jsonData = json.data(using: .utf8) {
do {
let message = try decoder.decode(personalInformation.self, from: jsonData)
print(message)
} catch {
print(error)
}
}
我们实例化JSONDecoder
的一个实例,然后将JSON
字符串转换为personalInformation
的对象。
运行下代码,我们可以看到,我们获得并展示了json
内的数据。
参数映射
在我们从服务器获得JSON
数据时,可能会出现我们实例化的参数和JSON
数据的参数不匹配的情况。
示例:在JSON
数据中,我们把city
城市换成cityName
城市名称。
这时候,我们就需要映射字段名称,而不需要每次都更改我们定义的字段。
enum CodingKeys: String, CodingKey {
case name
case country
case city = "cityName"
}
我们在personalInformation
个人信息结构体增加了一个枚举,然后使用case
转换参数进行映射。
对象嵌套
我们再考虑一种情况,如果JSON数据中存在嵌套关系,比如我们新增一个参数location
位置,在location
位置里放country
国家参数。
let json = """
{
"name": "Ricardo",
"location": {
"country": "China",
},
"cityName": "Guangzhou"
}
"""
这个例子很常见,我们可以把省、市、区放在地址里,这种对象中嵌套对象,我们处理也需要建立映射关系。
首先我们需要在CodingKeys
中设置切换。
enum CodingKeys: String, CodingKey {
case name
case country = "location"
case city = "cityName"
}
同时我们还需要定义了一个枚举LocationKeys
,它的参数是被location
位置嵌套的country
国家参数。
由于我们不能直接映射,那我们需要在Codable
协议的初始化器中来解码得到我们想要的值。
enum LocationKeys: String, CodingKey {
case country
}
然后是实现方法。
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
let location = try values.nestedContainer(keyedBy: LocationKeys.self, forKey: .country)
country = try location.decode(String.self, forKey: .country)
city = try values.decode(String.self, forKey: .city)
}
我们在init
函数方法中,调用decoder
的container
容器解码器方法来获取CodingKeys
枚举的数据,CodingKeys
枚举里有name
名字。
而由于country
国家参数在location
位置的容器中,就需要通过调用LocationKeys
枚举的nestedContainer
方法进一步解码城市的值。
以上就是嵌套对象解码JSON
数据的方法。
数据数组
在上面我们了解的都是基于1
行数据的解析,如果我们JSON
数据是由多行数据
组成的数组,我们又该如何解析呢?
let json = """
{
"messages":[
{
"name": "Ricardo",
"location": {
"country": "China",
},
"cityName": "Guangzhou"
},{
"name": "Ricardo",
"location": {
"country": "China",
},
"cityName": "Guangzhou"
}]
}
"""
我们的JSON
有一个messages
数组,里面有2
个数据行。
要想解析这个messages
数组,我们也是需要创建一个遵循Codable
可编码协议的结构体,这里命名为MessageArrays
。
struct MessageArrays: Codable {
var messages: [personalInformation]
}
我们用messages
来接收personalInformation
个人信息结构体的数据。
然后在解析这块,我们就不能直接解析personalInformation
的数据了,我们改为解析MessageArrays
数组的数据。
同时,我们用for
循环输出下数据看看效果:
let decoder = JSONDecoder()
if let jsonData = json.data(using: .utf8) {
do {
let messageArrays = try decoder.decode(MessageArrays.self, from: jsonData)
for message in messageArrays.messages {
print(message)
}
} catch {
print(error)
}
}
恭喜你,我们完成了JSON
数据的全部学习!
完整代码
import SwiftUI
//json数据准备
let json = """
{
"messages":[
{
"name": "Ricardo",
"location": {
"country": "China",
},
"cityName": "Guangzhou"
},{
"name": "Ricardo",
"location": {
"country": "China",
},
"cityName": "Guangzhou"
}]
}
"""
//定义数组
struct MessageArrays: Codable {
var messages: [personalInformation]
}
//定义模型
struct personalInformation: Codable {
var name: String
var country: String
var city: String
//定义参数枚举
enum CodingKeys: String, CodingKey {
case name
case country = "location"
case city = "cityName"
}
//数组枚举
enum LocationKeys: String, CodingKey {
case country
}
//实例化
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
let location = try values.nestedContainer(keyedBy: LocationKeys.self, forKey: .country)
country = try location.decode(String.self, forKey: .country)
city = try values.decode(String.self, forKey: .city)
}
}
//解析数据
let decoder = JSONDecoder()
if let jsonData = json.data(using: .utf8) {
do {
let messageArrays = try decoder.decode(MessageArrays.self, from: jsonData)
for message in messageArrays.messages {
print(message)
}
} catch {
print(error)
}
}
快来动手试试吧!
如果本专栏对你有帮助,不妨点赞、评论、关注~