Manuelles Anpassen der Codierungsschlüssel
In Ihrem Beispiel erhalten Sie eine automatisch generierte Konformität mit, Codable
da auch alle Ihre Eigenschaften übereinstimmen Codable
. Diese Konformität erstellt automatisch einen Schlüsseltyp, der einfach den Eigenschaftsnamen entspricht. Dieser wird dann verwendet, um aus einem einzelnen Schlüsselcontainer zu codieren / daraus zu decodieren.
Doch ein wirklich nettes Feature dieser automatisch generierten Übereinstimmung besteht darin , dass , wenn Sie definieren eine verschachtelte enum
in Ihrem Typ „bezeichnet CodingKeys
“ (oder eine Verwendung typealias
mit diesem Namen) , dass entspricht die CodingKey
Protokoll - Swift wird automatisch verwenden diese als Schlüsseltyp. Auf diese Weise können Sie die Schlüssel, mit denen Ihre Eigenschaften codiert / decodiert werden, einfach anpassen.
Das heißt also, Sie können einfach sagen:
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
}
}
Die Enum-Fallnamen müssen mit den Eigenschaftsnamen übereinstimmen, und die Rohwerte dieser Fälle müssen mit den Schlüsseln übereinstimmen, in die Sie codieren / von denen Sie decodieren (sofern nicht anders angegeben, entsprechen die Rohwerte einer String
Aufzählung den Fallnamen ). Daher wird die zip
Eigenschaft jetzt mit dem Schlüssel codiert / decodiert "zip_code"
.
Die genauen Regeln für die automatische Generierung Encodable
/ Decodable
Konformität sind im Evolutionsvorschlag (Schwerpunkt Mine) aufgeführt:
Zusätzlich zur automatischen CodingKey
Anforderungssynthese für
enums
können Encodable
& Decodable
Anforderungen auch für bestimmte Typen automatisch synthetisiert werden:
Typen, Encodable
deren Eigenschaften alle entsprechen, Encodable
erhalten automatisch generierte Enum-Mapping-Eigenschaften für String
Fallnamen CodingKey
. Ähnliches gilt für Decodable
Typen, deren Eigenschaften alle sindDecodable
Typen, die in (1) fallen - und Typen, die manuell einen CodingKey
enum
(benannten CodingKeys
, direkten oder über a typealias
) bereitstellen , dessen Fälle 1-zu-1 Encodable
/ Decodable
Eigenschaften nach Namen zuordnen - erhalten eine automatische Synthese von init(from:)
und encode(to:)
gegebenenfalls unter Verwendung dieser Eigenschaften und Schlüssel
Typen , die in keiner fallen (1) noch (2) wird eine benutzerdefinierte Schlüsseltyp zur Verfügung stellen müssen , falls erforderlich und stellen ihre eigenen init(from:)
und
encode(to:)
, gegebenenfalls
Beispielcodierung:
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"}
Beispieldecodierung:
// 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")
Automatische snake_case
JSON-Schlüssel für camelCase
Eigenschaftsnamen
Wenn Sie in Swift 4.1 Ihre zip
Eigenschaft in umbenennen zipCode
, können Sie die Schlüsselcodierungs- / Decodierungsstrategien für JSONEncoder
und nutzen JSONDecoder
, um Codierungsschlüssel zwischen camelCase
und automatisch zu konvertieren snake_case
.
Beispielcodierung:
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"}
Beispieldecodierung:
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")
Eine wichtige Anmerkung zu dieser Strategie ist jedoch, dass einige Eigenschaftsnamen nicht mit Akronymen oder Initialismen umgangen werden können, die gemäß den Swift API-Entwurfsrichtlinien (je nach Position) einheitlich in Groß- oder Kleinschreibung geschrieben werden sollten ).
Beispielsweise wird eine Eigenschaft mit dem Namen someURL
mit dem Schlüssel codiert some_url
, aber beim Decodieren wird diese in transformiert someUrl
.
Um dies zu beheben, müssen Sie den Codierungsschlüssel für diese Eigenschaft manuell als Zeichenfolge angeben, die der Decoder erwartet, z. B. someUrl
in diesem Fall (der some_url
vom Encoder weiterhin transformiert wird):
struct S : Codable {
private enum CodingKeys : String, CodingKey {
case someURL = "someUrl", someOtherProperty
}
var someURL: String
var someOtherProperty: String
}
(Dies beantwortet Ihre spezifische Frage nicht unbedingt, aber angesichts des kanonischen Charakters dieser Fragen und Antworten halte ich es für sinnvoll, sie einzubeziehen.)
Benutzerdefinierte automatische JSON-Schlüsselzuordnung
In Swift 4.1 können Sie die benutzerdefinierten Schlüsselcodierungs- / Decodierungsstrategien für JSONEncoder
und nutzen JSONDecoder
und eine benutzerdefinierte Funktion zum Zuordnen von Codierungsschlüsseln bereitstellen.
Die von Ihnen bereitgestellte Funktion verwendet a [CodingKey]
, das den Codierungspfad für den aktuellen Punkt beim Codieren / Decodieren darstellt (in den meisten Fällen müssen Sie nur das letzte Element berücksichtigen, dh den aktuellen Schlüssel). Die Funktion gibt a zurück CodingKey
, das den letzten Schlüssel in diesem Array ersetzt.
Beispiel: UpperCamelCase
JSON-Schlüssel für lowerCamelCase
Eigenschaftsnamen:
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
}
}
}
Sie können jetzt mit der .convertToUpperCamelCase
Schlüsselstrategie codieren :
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"}
und mit der .convertFromUpperCamelCase
Schlüsselstrategie dekodieren :
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
Aufzählung; Kann ich nur den einen Schlüssel auflisten, den ich ändere?