코딩 키 수동 사용자 지정
귀하의 예에서는 Codable
모든 속성이 Codable
. 이 적합성은 단순히 속성 이름에 해당하는 키 유형을 자동으로 생성합니다.이 키 유형은 단일 키 컨테이너에서 인코딩 / 디코딩하는 데 사용됩니다.
그러나이 자동 생성 적합성의 정말 멋진 기능 중 하나 는 프로토콜 을 준수 하는 enum
" CodingKeys
"(또는 typealias
이 이름과 함께를 사용) 라는 유형에 중첩을 정의하면 CodingKey
Swift 가이 를 자동으로 키 유형 으로 사용한다는 것 입니다. 따라서 속성이 인코딩 / 디코딩되는 키를 쉽게 사용자 지정할 수 있습니다.
이것이 의미하는 바는 다음과 같이 말할 수 있다는 것입니다.
struct Address : Codable {
var street: String
var zip: String
var city: String
var state: String
private enum CodingKeys : String, CodingKey {
case street, zip = "zip_code", city, state
}
}
열거 형 케이스 이름은 속성 이름과 일치해야하며 이러한 케이스의 원시 값은 인코딩 / 디코딩 대상 키와 일치해야합니다 (달리 지정하지 않는 한 String
열거 형 의 원시 값은 케이스 이름과 동일합니다.) ). 따라서 zip
속성은 이제 키를 사용하여 인코딩 / 디코딩됩니다 "zip_code"
.
자동 생성 Encodable
/ Decodable
적합성에 대한 정확한 규칙 은 진화 제안 (강조 내)에 자세히 설명되어 있습니다 .
자동 이외에 CodingKey
대한 요구 합성
enums
, Encodable
및 Decodable
요구 자동 아니라 특정 유형으로 합성 될 수있다 :
해당 Encodable
속성을 모두 준수하는 유형 은 케이스 이름에 Encodable
대한 자동 생성 String
지원 CodingKey
열거 형 매핑 속성을 가져옵니다 . Decodable
속성이 모두 인 유형의 경우 유사 합니다.Decodable
(1)에 떨어지는 유형 - 수동으로 제공하고, A 형 CodingKey
enum
(이름 CodingKeys
, 직접, 또는 통해 typealias
) 그 경우 1 대 1로지도 Encodable
/ Decodable
이름 속성 - 자동 합성 수 init(from:)
와 encode(to:)
그 속성과 키를 사용하여, 적절한를
(1)과 (2) 모두에 해당하지 않는 유형은 필요한 경우 사용자 정의 키 유형을 제공하고 적절한 경우 자체 init(from:)
및을
제공해야합니다.encode(to:)
인코딩 예 :
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)
}
//{"state":"California","street":"Apple Bay Street","zip_code":"94608","city":"Emeryville"}
디코딩 예 :
// using the """ multi-line string literal here, as introduced in SE-0168,
// to avoid escaping the quotation marks
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)
}
// Address(street: "Apple Bay Street", zip: "94608",
// city: "Emeryville", state: "California")
속성 이름에 snake_case
대한 자동 JSON 키camelCase
당신이 당신의 이름을 바꾸면 스위프트 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()
encoder.keyEncodingStrategy = .convertToSnakeCase
let encoded = try encoder.encode(address)
print(String(decoding: encoded, as: UTF8.self))
} catch {
print(error)
}
//{"state":"California","street":"Apple Bay Street","zip_code":"94608","city":"Emeryville"}
디코딩 예 :
let jsonString = """
{"state":"California","street":"Apple Bay Street","zip_code":"94608","city":"Emeryville"}
"""
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decoded = try decoder.decode(Address.self, from: Data(jsonString.utf8))
print(decoded)
} catch {
print(error)
}
// Address(street: "Apple Bay Street", zipCode: "94608",
// city: "Emeryville", state: "California")
그러나이 전략에 대해 주목해야 할 한 가지 중요한 점은 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
}
(이것은 귀하의 특정 질문에 엄격하게 대답하지는 않지만이 Q & A의 표준 특성을 고려할 때 포함 할 가치가 있다고 생각합니다)
사용자 지정 자동 JSON 키 매핑
Swift 4.1에서는 및에서 사용자 지정 키 인코딩 / 디코딩 전략을 활용 JSONEncoder
하여 JSONDecoder
코딩 키를 매핑하는 사용자 지정 함수를 제공 할 수 있습니다.
제공하는 함수 [CodingKey]
는 인코딩 / 디코딩의 현재 지점에 대한 코딩 경로를 나타내는를 사용합니다 (대부분의 경우 마지막 요소, 즉 현재 키만 고려하면됩니다). 함수는 CodingKey
이 배열의 마지막 키를 대체 할 a 를 반환합니다 .
예를 들어 속성 이름에 UpperCamelCase
대한 JSON 키는 lowerCamelCase
다음과 같습니다.
import Foundation
// wrapper to allow us to substitute our mapped string keys.
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!)
// uppercase first letter
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!)
// lowercase first letter
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)
}
//{"Street":"Apple Bay Street","City":"Emeryville","State":"California","ZipCode":"94608"}
.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)
}
// Address(street: "Apple Bay Street", zipCode: "94608",
// city: "Emeryville", state: "California")
CodingKeys
열거 형 아래에 있습니다 . 변경중인 키 하나만 나열해도됩니까?