示例编码:
import Foundation
let address = Address(street: "Apple Bay Street", zip: "94608",
city: "Emeryville", state: "California")
do {
let encoded = try JSONEncoder().encode(address)
print(String(decoding: encoded, as: UTF8.self))
} catch {
print(error)
}
例子解码:
let jsonString = """
{"state":"California","street":"Apple Bay Street","zip_code":"94608","city":"Emeryville"}
"""
do {
let decoded = try JSONDecoder().decode(Address.self, from: Data(jsonString.utf8))
print(decoded)
} catch {
print(error)
}
自动将camelCase
属性名转换为snake_case
的JSON键
在Swift 4.1中,如果将您的zip
属性重命名为zipCode
,则可以利用JSONEncoder
和JSONDecoder
上的键编码/解码策略,以便自动在camelCase
和snake_case
之间转换编码键。
例如编码:
import Foundation
struct Address : Codable {
var street: String
var zipCode: String
var city: String
var state: String
}
let address = Address(street: "Apple Bay Street", zipCode: "94608",
city: "Emeryville", state: "California")
do {
let encoder = JSONEncoder()
<b>encoder.keyEncodingStrategy = .convertToSnakeCase</b>
let encoded = try encoder.encode(address)
print(String(decoding: encoded, as: UTF8.self))
} catch {
print(error)
}
示例解码:
let jsonString = """
{"state":"California","street":"Apple Bay Street","zip_code":"94608","city":"Emeryville"}
"""
do {
let decoder = JSONDecoder()
<b>decoder.keyDecodingStrategy = .convertFromSnakeCase</b>
let decoded = try decoder.decode(Address.self, from: Data(jsonString.utf8))
print(decoded)
} catch {
print(error)
}
重要的一点是,这种策略无法往返某些缩写或首字母缩写的属性名称,根据Swift API设计准则,这些缩写应该统一大写或小写(取决于位置)。
例如,命名为someURL
的属性将使用键some_url
进行编码,但在解码时,它将被转换为someUrl
。
要解决这个问题,您需要手动指定该属性的编码键为解码器预期的字符串,例如,在这种情况下是someUrl
(但编码器仍会将其转换为some_url
)。
struct S : Codable {
private enum CodingKeys : String, CodingKey {
case someURL = "someUrl", someOtherProperty
}
var someURL: String
var someOtherProperty: String
}
自定义自动JSON键映射
在Swift 4.1中,您可以利用JSONEncoder
和JSONDecoder
上的自定义键编码/解码策略,从而为编码键提供自定义函数。
您提供的函数接受一个[CodingKey]
,表示当前编码/解码路径(在大多数情况下,您只需要考虑最后一个元素;也就是当前键)。该函数返回一个CodingKey
,将替换此数组中的最后一个键。
例如,将lowerCamelCase
属性名称的UpperCamelCase
JSON键:
import Foundation
struct AnyCodingKey : CodingKey {
var stringValue: String
var intValue: Int?
init(_ base: CodingKey) {
self.init(stringValue: base.stringValue, intValue: base.intValue)
}
init(stringValue: String) {
self.stringValue = stringValue
}
init(intValue: Int) {
self.stringValue = "\(intValue)"
self.intValue = intValue
}
init(stringValue: String, intValue: Int?) {
self.stringValue = stringValue
self.intValue = intValue
}
}
extension JSONEncoder.KeyEncodingStrategy {
static var convertToUpperCamelCase: JSONEncoder.KeyEncodingStrategy {
return .custom { codingKeys in
var key = AnyCodingKey(codingKeys.last!)
if let firstChar = key.stringValue.first {
let i = key.stringValue.startIndex
key.stringValue.replaceSubrange(
i ... i, with: String(firstChar).uppercased()
)
}
return key
}
}
}
extension JSONDecoder.KeyDecodingStrategy {
static var convertFromUpperCamelCase: JSONDecoder.KeyDecodingStrategy {
return .custom { codingKeys in
var key = AnyCodingKey(codingKeys.last!)
if let firstChar = key.stringValue.first {
let i = key.stringValue.startIndex
key.stringValue.replaceSubrange(
i ... i, with: String(firstChar).lowercased()
)
}
return key
}
}
}
现在,您可以使用.convertToUpperCamelCase键策略进行编码:
let address = Address(street: "Apple Bay Street", zipCode: "94608",
city: "Emeryville", state: "California")
do {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToUpperCamelCase
let encoded = try encoder.encode(address)
print(String(decoding: encoded, as: UTF8.self))
} catch {
print(error)
}
使用.convertFromUpperCamelCase
键策略进行解码:
let jsonString = """
{"Street":"Apple Bay Street","City":"Emeryville","State":"California","ZipCode":"94608"}
"""
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromUpperCamelCase
let decoded = try decoder.decode(Address.self, from: Data(jsonString.utf8))
print(decoded)
} catch {
print(error)
}
"
即可:@MartinR - HamishCodable
)。 - HamishAddress
的初始化器中使用嵌套容器作为示例,但这样做会不必要地将您自己绑定到解码从父对象图中特定位置开始的JSON对象。更好的方法是将起始键路径抽象到解码器本身 - 这里是一个粗略的hackey-ish实现。 - HamishcodingKeys.last
会给你当前的编码键,数组中所有先前的元素都是给定编码路径的父编码键。例如,在解码{"foo": {"bar": "baz"}}
时,当应用键解码策略到"bar"
时,codingKeys
将是["foo", "bar"]
。 - Hamish