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 typealias
için uygundur bu isimde) CodingKey
protokolü - 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, String
numaralandı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
/ Decodable
uygunluk için kesin kurallar , evrim önerisinde ayrıntılı olarak belirtilmiştir (vurgu benim):
Otomatik CodingKey
gereksinim sentezine
ek olarak enums
, Encodable
& Decodable
gereksinimler belirli türler için de otomatik olarak sentezlenebilir:
Uygun tipleri Encodable
, özellikleri hepsi Encodable
otomatik olarak oluşturulmuş olsun String
-backed CodingKey
vaka adlarına enum haritalama özellikleri. Benzer şekilde Decodable
tüm özellikleri olan türler içinDecodable
(1) 'e düşen türlerCodingKey
enum
CodingKeys
typealias
Encodable
Decodable
- 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_case
için otomatik JSON anahtarlarıcamelCase
Eğer adlandırmak eğer Swift 4.1 yılında zip
mülkü zipCode
, üzerinde stratejiler deşifre / anahtar kodlama yararlanabilir JSONEncoder
ve JSONDecoder
otomatik amacıyla arasındaki kodlama anahtarları dönüştürmek camelCase
ve 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 someURL
anahtarla 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 someUrl
bu durumda ( some_url
kodlayı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 JSONEncoder
ve JSONDecoder
kodlama 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ı UpperCamelCase
iç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 .convertToUpperCamelCase
anahtar 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 .convertFromUpperCamelCase
anahtar 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")
CodingKeys
enum altında ; sadece değiştirdiğim anahtarı listeleyebilir miyim?