ปรับแต่งคีย์การเข้ารหัสด้วยตนเอง
ในตัวอย่างของคุณคุณจะได้รับความสอดคล้องที่สร้างขึ้นโดยอัตโนมัติCodable
เนื่องจากคุณสมบัติทั้งหมดของคุณเป็นไปตามCodable
ด้วย ความสอดคล้องนี้จะสร้างประเภทคีย์โดยอัตโนมัติซึ่งสอดคล้องกับชื่อคุณสมบัติซึ่งจะถูกใช้เพื่อเข้ารหัส / ถอดรหัสจากคอนเทนเนอร์ที่มีคีย์เดียว
อย่างไรก็ตามหนึ่งจริงๆคุณลักษณะเรียบร้อยของนี้สอดคล้องสร้างขึ้นโดยอัตโนมัติคือว่าถ้าคุณกำหนดซ้อนกันenum
ในรูปแบบของคุณเรียกว่า " CodingKeys
" (หรือใช้typealias
ชื่อนี้) ที่สอดคล้องกับCodingKey
โพรโทคอ - สวิฟท์โดยอัตโนมัติจะใช้นี้เป็นชนิดที่สำคัญ ดังนั้นจึงช่วยให้คุณปรับแต่งคีย์ที่คุณสมบัติของคุณเข้ารหัส / ถอดรหัสด้วย
สิ่งนี้หมายความว่าคุณสามารถพูดได้ว่า:
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 ต้องตรงกับชื่อคุณสมบัติและค่าดิบของเคสเหล่านี้ต้องตรงกับคีย์ที่คุณกำลังเข้ารหัส / ถอดรหัสจาก (เว้นแต่จะระบุไว้เป็นอย่างอื่นค่าดิบของการString
แจงนับจะเหมือนกับชื่อเคส ). ดังนั้นzip
สถานที่ให้บริการในขณะนี้จะมีการเข้ารหัส / "zip_code"
ถอดรหัสโดยใช้กุญแจ
กฎที่แน่นอนสำหรับการสร้างEncodable
/ ความDecodable
สอดคล้องโดยอัตโนมัติมีรายละเอียดตามข้อเสนอวิวัฒนาการ (เน้นของฉัน):
นอกจากอัตโนมัติCodingKey
สังเคราะห์ต้องการสำหรับ
enums
, Encodable
และDecodable
ข้อกำหนดสามารถสังเคราะห์โดยอัตโนมัติบางประเภทเช่นกัน:
ประเภทที่สอดคล้องกับEncodable
ที่มีคุณสมบัติทั้งหมดที่Encodable
ได้รับการสร้างขึ้นโดยอัตโนมัติString
-backed CodingKey
คุณสมบัติการทำแผนที่ enum ชื่อกรณี ในทำนองเดียวกันสำหรับDecodable
ประเภทที่มีคุณสมบัติทั้งหมดDecodable
ประเภทที่อยู่ใน (1) - และประเภทที่ระบุCodingKey
enum
(ตั้งชื่อCodingKeys
โดยตรงหรือผ่าน a typealias
) ด้วยตนเองซึ่งกรณีที่แมป 1-to-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)
}
ตัวอย่างการถอดรหัส:
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)
}
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)
}
ตัวอย่างการถอดรหัส:
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)
}
สิ่งสำคัญอย่างหนึ่งที่ควรทราบเกี่ยวกับกลยุทธ์นี้ก็คือจะไม่สามารถไป - กลับชื่อคุณสมบัติบางอย่างที่มีตัวย่อหรือการเริ่มต้นซึ่งตามแนวทางการออกแบบ 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
ช่วยให้คุณสามารถจัดเตรียมฟังก์ชันที่กำหนดเองเพื่อแมปคีย์การเข้ารหัส
ฟังก์ชันที่คุณระบุจะใช้ a [CodingKey]
ซึ่งแสดงถึงเส้นทางการเข้ารหัสสำหรับจุดปัจจุบันในการเข้ารหัส / ถอดรหัส (ในกรณีส่วนใหญ่คุณจะต้องพิจารณาเฉพาะองค์ประกอบสุดท้ายนั่นคือคีย์ปัจจุบัน) ฟังก์ชันจะส่งคืน a CodingKey
ที่จะแทนที่คีย์สุดท้ายในอาร์เรย์นี้
ตัวอย่างเช่นUpperCamelCase
คีย์ JSON สำหรับlowerCamelCase
ชื่อคุณสมบัติ:
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)
}
CodingKeys
enum; ฉันสามารถระบุคีย์เดียวที่ฉันกำลังเปลี่ยนแปลงได้ไหม