使用中间类型在Swift中解码JSON
基础
要解码JSON结构并将应用程序中的模型编码回JSON,您可以使模型符合Swift Codable
协议。 这是另外两个协议的组合: Decodable
和Encodable
。
这对于简单的JSON数组和字典非常有用,例如:
让json =“”“
[
{
“名称”:“年度旅行保险”,
“ paymentFrequency”:“每年”,
“ description”:“全年安全旅行。”
},
{
“名称”:“汽车保险”,
“ paymentFrequency”:“每月”
}
]
“”“ .data(使用:.utf8)!
您可以使模型符合Codable
(或Decodable
)协议:
struct BankProduct:可编码 {
变量名称:字符串
var paymentFrequency:付款频率
var说明:字符串?
枚举PaymentFrequency:字符串,可编码{
每月个案
每年一次
}
}
只要JSON数组中没有其他不代表我们模型的元素,所有内容都会自动解码。 否则,解码将失败。 这意味着我们可以在JSON结构的每个元素中添加额外的键,但是键name
和category
应始终位于该元素中,因为它们在我们的模型中不是可选的。
在此示例中,还添加了一个枚举,因此您可以看到,只要枚举符合(De)Codable
协议且枚举的大小写名称与中的字符串相同,它就会自动将JSON转换为正确的大小写。 JSON。 否则,您需要为案例提供一个rawValue
。
我们可以使用以下方法从JSON创建对象:
让解码器= JSONDecoder()
让产品=尝试解码器。解码([BankProduct] .self,来自:json)
当JSON的键名与模型中属性的名称不匹配时,我们需要一个名为CodingKeys
的嵌套枚举,其枚举类型应符合CodingKey
协议,它的String
rawValue类型。 枚举应包含所有键,即使在模型和JSON中具有相同名称的键也是如此。 但是对于最后这些,您无需提供rawValue
。
让json =“”“
[
{
“ product_name” :“年度旅行保险”,
“ payment_frequency” :“每年”,
“ description ”:“全年安全。”
},
{
“ product_name” :“汽车保险”,
“ payment_frequency” :“每月”
}
]
“”“ .data(使用:.utf8)!
struct BankProduct:可编码{
...
私有枚举CodingKeys : 字符串 , CodingKey {
案例名称 =“ product_name ”
案例付款频率 = “ 付款频率 ”
案例描述
}
}
但是,当您在应用程序中建模的概念的结构与JSON的结构不一致时,该怎么办?
使用中间类型
可能是模型的某些数据散布在JSON中的多个嵌套对象中。 在下一个示例中,您将看到API返回的JSON包含比所需更多的信息,并且我们要建模的数据嵌套在其他结构内:
让json =“”“
[
{
“名称”:“银行1”,
“类别”:[
{
“ name”:“保险”,
“子类别”:[
{
“ name”:“旅行”,
“产品”:{
“名称”:“年度旅行保险”,
“ paymentFrequency”:“每年”,
“ description”:“全年安全旅行。”
}
},
{
“名称”:“汽车”,
“产品”:{
“名称”:“汽车保险”,
“ paymentFrequency”:“每月”
}
}
]
}
]
},
{
“名称”:“银行2”,
“类别”:[
{
“ name”:“付款”,
“子类别”:[
{
“名称”:“信用卡”,
“产品”:{
“ name”:“ Platinumcard”,
“ paymentFrequency”:“每年”
}
}
]
}
]
}
]
“”“ .data(使用:.utf8)!
在我们的示例中,我们有一个代表银行的类型和产品列表:
struct银行{
变量名称:字符串
var产品:[产品]
结构产品:可编码{
变量名称:字符串
var paymentFrequency:付款频率
var说明:字符串?
}
}
您会看到Bank
结构与JSON结构不兼容,该JSON结构的subcategories
和categories
结构中包含产品。 为了弥合这一差距,我们可以创建一个中间类型:
struct BankService:可解码{
命名:字符串
出租类别:[类别]
结构类别:可分解{
命名:字符串
let子类别:[子类别]
struct子类别:可降解{
命名:字符串
设产品:Bank.Product
}
}
}
BankService
现在匹配JSON的结构。 当协议也包含在嵌套类型中时,对Decodable
的一致性是自动的。 由于此处的名称和类型相同,因此在Subcategory
类型中可以重复使用Bank
的嵌套Product
类型。 在Bank
的扩展中,我们现在可以添加一个带有BankService
实例并删除嵌套的初始化程序:
扩展银行{
初始化(来自服务:BankService){
名称= service.name
产品= []
用于service.categories中的类别{
用于category.subcategories {
products.append(subcategory.product)
}
}
}
}
现在,您可以读取JSON,将其传递给中间类型,然后在应用程序中使用生成的Bank
实例:
让解码器= JSONDecoder()
让服务=尝试解码器.decode([BankService] .self,来自:json)
让bank = services.map {Bank(from:$ 0)}