Kodlama anahtarlarını manuel olarak özelleştirme
Örneğinizde Codable, tüm mülklerinizin de uyduğu için otomatik olarak oluşturulmuş bir uyum elde ediyorsunuz Codable. Bu uygunluk otomatik olarak özellik adlarına karşılık gelen bir anahtar türü oluşturur - bu daha sonra tek bir anahtarlı kapsayıcıdan kodlama / kod çözme için kullanılır.
Ancak tek gerçekten otomatik olarak oluşturulan bu uygunluk özellik düzgün olduğunu bir yuvalanmış tanımlarsanız enum"adlı tipinde CodingKeys" (ya da kullanmak typealiasiçin uygundur bu isimde) CodingKeyprotokolü - Swift otomatik kullanacağı bu anahtar türü olarak. Bu nedenle, özelliklerinizin kodlandığı / kodunun çözüldüğü anahtarları kolayca özelleştirmenize olanak tanır.
Yani bunun anlamı şudur:
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
}
}
Enum vaka adlarının özellik adlarıyla eşleşmesi gerekir ve bu vakaların ham değerlerinin kodladığınız / kod çözdüğünüz anahtarlarla eşleşmesi gerekir (aksi belirtilmedikçe, Stringnumaralandırmanın ham değerleri vaka adlarıyla aynı olacaktır. ). Bu nedenle, zipözellik artık anahtar kullanılarak kodlanacak / kodu çözülecektir "zip_code".
Otomatik oluşturulan Encodable/ Decodableuygunluk için kesin kurallar , evrim önerisinde ayrıntılı olarak belirtilmiştir (vurgu benim):
Otomatik CodingKeygereksinim sentezine
ek olarak enums, Encodable& Decodablegereksinimler belirli türler için de otomatik olarak sentezlenebilir:
Uygun tipleri Encodable, özellikleri hepsi Encodableotomatik olarak oluşturulmuş olsun String-backed CodingKeyvaka adlarına enum haritalama özellikleri. Benzer şekilde Decodabletüm özellikleri olan türler içinDecodable
(1) 'e düşen türlerCodingKey enumCodingKeystypealiasEncodableDecodable - ve durumları 1'e 1'i / özellikleri ada göre eşleyen manuel olarak (adlandırılmış , doğrudan veya a yoluyla ) sağlayan türler - bu özelliklerin ve anahtarların otomatik sentezini init(from:)ve encode(to:)uygun şekilde elde edin
Ne (1) ne de (2) kapsamına giren türlerin, gerekirse özel bir anahtar türü sağlaması ve kendi anahtarlarını init(from:)ve
encode(to:)uygun şekilde
Örnek kodlama:
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"}
Örnek kod çözme:
// 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")
Özellik adları snake_caseiçin otomatik JSON anahtarlarıcamelCase
Eğer adlandırmak eğer Swift 4.1 yılında zipmülkü zipCode, üzerinde stratejiler deşifre / anahtar kodlama yararlanabilir JSONEncoderve JSONDecoderotomatik amacıyla arasındaki kodlama anahtarları dönüştürmek camelCaseve snake_case.
Örnek kodlama:
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"}
Örnek kod çözme:
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")
Bununla birlikte, bu strateji hakkında dikkat edilmesi gereken önemli bir nokta, Swift API tasarım yönergelerine göre (konuma bağlı olarak tekdüze olarak büyük veya küçük harf olması gereken kısaltmalar veya baş harflerle bazı özellik adlarını geri alamayacağıdır). ).
Örneğin, adı verilen bir özellik someURLanahtarla kodlanacak some_url, ancak kod çözüldüğünde bu dönüştürülecektir someUrl.
Bunu düzeltmek için, bu özelliğin kodlama anahtarını kod çözücünün beklediği dize olacak şekilde manuel olarak belirtmeniz gerekir, örneğin someUrlbu durumda ( some_urlkodlayıcı tarafından hala dönüştürülecektir ):
struct S : Codable {
private enum CodingKeys : String, CodingKey {
case someURL = "someUrl", someOtherProperty
}
var someURL: String
var someOtherProperty: String
}
(Bu, sorunuzu kesin olarak yanıtlamaz, ancak bu Soru-Cevap bölümünün kanonik doğası göz önüne alındığında, buna değer olduğunu düşünüyorum)
Özel otomatik JSON anahtar eşleme
Swift 4.1'de, özel anahtar kodlama / kod çözme stratejilerinden faydalanabilir JSONEncoderve JSONDecoderkodlama anahtarlarını eşlemek için özel bir işlev sağlamanıza olanak tanır.
Sağladığınız işlev [CodingKey], kodlama / kod çözmede geçerli noktanın kodlama yolunu temsil eden a alır (çoğu durumda, yalnızca son öğeyi, yani geçerli anahtarı dikkate almanız gerekir). İşlev CodingKey, bu dizideki son anahtarın yerini alacak bir a döndürür .
Örneğin, özellik adları UpperCamelCaseiçin JSON anahtarları 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
}
}
}
Artık .convertToUpperCamelCaseanahtar strateji ile kodlayabilirsiniz :
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"}
ve .convertFromUpperCamelCaseanahtar strateji ile kod çözme :
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")
CodingKeysenum altında ; sadece değiştirdiğim anahtarı listeleyebilir miyim?