Swift 4通过Decodable协议引入了对原生JSON编码和解码的支持 . 我如何使用自定义键?
例如,说我有一个结构
struct Address:Codable {
var street:String
var zip:String
var city:String
var state:String
}
我可以将其编码为JSON .
let address = Address(street: "Apple Bay Street", zip: "94608", city: "Emeryville", state: "California")
if let encoded = try? encoder.encode(address) {
if let json = String(data: encoded, encoding: .utf8) {
// Print JSON String
print(json)
// JSON string is
{ "state":"California",
"street":"Apple Bay Street",
"zip":"94608",
"city":"Emeryville"
}
}
}
我可以将它编码回一个对象 .
let newAddress: Address = try decoder.decode(Address.self, from: encoded)
但如果我有一个json对象
{
"state":"California",
"street":"Apple Bay Street",
"zip_code":"94608",
"city":"Emeryville"
}
我如何告诉 Address
解码器 zip_code
映射到 zip
?我相信你使用新的 CodingKey
协议,但我无法弄清楚如何使用它 .
3 回答
手动自定义编码密钥
在您的示例中,您将获得与Codable的自动生成的一致性,因为您的所有属性也符合
Codable
. 此一致性自动创建一个简单对应于属性名称的密钥类型 - 然后使用该密钥类型从单个密钥容器进行编码/解码 .但是,这种自动生成的一致性的一个非常巧妙的特性是,如果您在类型中定义了一个名为“
CodingKeys
”的嵌套_1131524(或使用具有此名称的typealias
)符合CodingKey协议 - Swift将自动将其用作关键字类型 . 因此,您可以轻松自定义用于编码/解码属性的键 .那么这意味着你可以说:
枚举案例名称需要与属性名称匹配,并且这些案例的原始值需要与您要编码/解码的键匹配(除非另有说明,
String
枚举的原始值将与案例相同)名) . 因此,现在将使用键"zip_code"
对zip
属性进行编码/解码 .自动生成Encodable / Decodable一致性的确切规则详见the evolution proposal(强调我的):
编码示例:
解码示例:
camelCase属性名称的自动snake_case JSON密钥
在Swift 4.1中,如果将
zip
属性重命名为zipCode
,则可以利用JSONEncoder
和JSONDecoder
上的密钥编码/解码策略,以自动转换camelCase
和snake_case
之间的编码密钥 .编码示例:
解码示例:
然而,关于这个策略需要注意的一个重要事项是,它无法使用首字母缩略词或首字母缩略词对某些属性名称进行往返,根据Swift API design guidelines,它应该是统一的大写或小写(取决于位置) .
例如,名为
someURL
的属性将使用键some_url
进行编码,但在解码时,将转换为someUrl
.要解决此问题,您必须手动将该属性的编码密钥指定为解码器所期望的字符串,例如
someUrl
(在这种情况下仍将由编码器转换为some_url
):(这并没有严格回答您的具体问题,但考虑到此问答的规范性质,我觉得值得包括)
自定义自动JSON键映射
在Swift 4.1中,您可以利用
JSONEncoder
和JSONDecoder
上的自定义键编码/解码策略,允许您提供自定义函数来映射编码键 .您提供的函数采用
[CodingKey]
,它表示编码/解码中当前点的编码路径(在大多数情况下,您只需要考虑最后一个元素;即当前键) . 该函数返回CodingKey
,它将替换此数组中的最后一个键 .例如,
UpperCamelCase
lowerCamelCase
属性名称的JSON键:你现在可以使用
.convertToUpperCamelCase
密钥策略进行编码:并使用
.convertFromUpperCamelCase
密钥策略进行解码:使用Swift 4.2,根据您的需要,您可以使用以下3种策略之一,以使您的模型对象自定义属性名称与您的JSON键匹配 .
#1 . 使用自定义编码键
使用以下实现声明符合
Codable
(Decodable
和Encodable
协议)的结构时......编译器会自动为您生成符合
CodingKey
协议的嵌套枚举 .因此,如果序列化数据格式中使用的键与数据类型中的属性名称不匹配,则可以手动实现此枚举并为所需的案例设置相应的
rawValue
.以下示例显示了如何执行:
#2 . 使用蛇案对骆驼案的关键编码策略
如果您的JSON具有蛇形键并且您希望将它们转换为模型对象的驼峰属性,则可以将
JSONEncoder
的keyEncodingStrategy和JSONDecoder
的keyDecodingStrategy属性设置为.convertToSnakeCase
.以下示例显示了如何执行:
#3 . 使用自定义密钥编码策略
如有必要,
JSONEncoder
和JSONDecoder
允许您设置自定义策略以使用JSONEncoder.KeyEncodingStrategy.custom(_:)和JSONDecoder.KeyDecodingStrategy.custom(_:)映射编码键 .以下示例显示了如何实现它们:
资料来源:
Apple developer documentation: "Encoding and Decoding Custom Types"
WWDC 2017 session 212: "What's new in Foundation"
MartianCraft: "Implementing a custom key strategy for coding types"
我所做的就是创建自己的结构,就像你从JSON获得的数据类型一样 .
像这样:
在此之后,您需要使用
CodingKey
创建相同结构的struct
扩展decodable
和enum
的扩展,然后您需要使用此枚举及其键和数据类型初始化解码器(键将来自枚举,数据类型将来自或说从结构本身引用)您需要根据需要在此处更改每个键和数据类型,并将其与解码器一起使用 .