使用中间类型在Swift中解码JSON

基础

要解码JSON结构并将应用程序中的模型编码回JSON,您可以使模型符合Swift Codable协议。 这是另外两个协议的组合: DecodableEncodable

这对于简单的JSON数组和字典非常有用,例如:

 让json =“”“ 
[
{
“名称”:“年度旅行保险”,
“ paymentFrequency”:“每年”,
“ description”:“全年安全旅行。”
},
{
“名称”:“汽车保险”,
“ paymentFrequency”:“每月”
}
]
“”“ .data(使用:.utf8)!

您可以使模型符合Codable (或Decodable )协议:

  struct BankProduct:可编码 { 
变量名称:字符串
var paymentFrequency:付款频率
var说明:字符串?

枚举PaymentFrequency:字符串,可编码{
每月个案
每年一次
}
}

只要JSON数组中没有其他不代表我们模型的元素,所有内容都会自动解码。 否则,解码将失败。 这意味着我们可以在JSON结构的每个元素中添加额外的键,但是键namecategory应始终位于该元素中,因为它们在我们的模型中不是可选的。

在此示例中,还添加了一个枚举,因此您可以看到,只要枚举符合(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结构的subcategoriescategories结构中包含产品。 为了弥合这一差距,我们可以创建一个中间类型:

  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)}

Interesting Posts