Encodable
/ Decodable
Protocols baru Swift 4 membuat serialisasi JSON (de) cukup menyenangkan. Namun, saya belum menemukan cara untuk memiliki kontrol yang sangat baik atas properti mana yang harus dikodekan dan mana yang harus didekodekan.
Saya telah memperhatikan bahwa mengecualikan properti dari CodingKeys
enum yang menyertai mengecualikan properti dari proses sama sekali, tetapi adakah cara untuk memiliki kontrol yang lebih halus?
CodingKeys
enum sudah cukup.Codable
protokol (init(from:)
danencode(to:)
) secara manual untuk kontrol penuh atas proses tersebut.Jawaban:
Daftar kunci untuk disandikan / didekode dikendalikan oleh jenis yang disebut
CodingKeys
(perhatikans
di akhir). Kompilator dapat mensintesiskan ini untuk Anda tetapi selalu dapat menimpanya.Misalkan Anda ingin mengecualikan properti
nickname
dari encoding dan decoding:struct Person: Codable { var firstName: String var lastName: String var nickname: String? private enum CodingKeys: String, CodingKey { case firstName, lastName } }
Jika Anda ingin asimetris (yaitu, menyandikan tetapi tidak mendekode atau sebaliknya), Anda harus menyediakan implementasi Anda sendiri dari
encode(with encoder: )
daninit(from decoder: )
:struct Person: Codable { var firstName: String var lastName: String // Since fullName is a computed property, it's excluded by default var fullName: String { return firstName + " " + lastName } private enum CodingKeys: String, CodingKey { case firstName case lastName case fullName } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) firstName = try container.decode(String.self, forKey: .firstName) lastName = try container.decode(String.self, forKey: .lastName) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(firstName, forKey: .firstName) try container.encode(lastName, forKey: .lastName) try container.encode(fullName, forKey: .fullName) } }
sumber
nickname
nilai default agar ini berfungsi. Jika tidak, tidak ada nilai yang dapat ditetapkan ke properti diinit(from:)
.encode
dalam contoh asimetris? Karena itu masih perilaku standar, saya rasa itu tidak diperlukan. Hanyadecode
karena itu di mana asimetri itu berasal.fullName
tidak dapat dipetakan ke properti tersimpan, Anda harus menyediakan pembuat enkode dan dekoder khusus.CodingKeys
. Jadi,var nickname: String { get { "name" } }
seharusnya sudah cukup.Jika kita perlu mengecualikan decoding beberapa properti dari sekumpulan besar properti dalam struktur, deklarasikan sebagai properti opsional. Kode untuk membuka bungkus opsional kurang dari menulis banyak kunci di bawah enum CodingKey.
Saya akan merekomendasikan menggunakan ekstensi untuk menambahkan properti contoh yang dihitung dan properti tipe yang dihitung. Ini memisahkan properti comforming yang dapat dikodekan dari logika lain sehingga memberikan keterbacaan yang lebih baik.
sumber
Cara lain untuk mengecualikan beberapa properti dari pembuat enkode, wadah pengkodean terpisah dapat digunakan
struct Person: Codable { let firstName: String let lastName: String let excludedFromEncoder: String private enum CodingKeys: String, CodingKey { case firstName case lastName } private enum AdditionalCodingKeys: String, CodingKey { case excludedFromEncoder } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let anotherContainer = try decoder.container(keyedBy: AdditionalCodingKeys.self) firstName = try container.decode(String.self, forKey: .firstName) lastName = try container.decode(String.self, forKey: .lastName) excludedFromEncoder = try anotherContainer(String.self, forKey: . excludedFromEncoder) } // it is not necessary to implement custom encoding // func encode(to encoder: Encoder) throws // let person = Person(firstName: "fname", lastName: "lname", excludedFromEncoder: "only for decoding") // let jsonData = try JSONEncoder().encode(person) // let jsonString = String(data: jsonData, encoding: .utf8) // jsonString --> {"firstName": "fname", "lastName": "lname"} }
pendekatan yang sama dapat digunakan untuk decoder
sumber
Anda dapat menggunakan properti yang dihitung:
struct Person: Codable { var firstName: String var lastName: String var nickname: String? var nick: String { get { nickname ?? "" } } private enum CodingKeys: String, CodingKey { case firstName, lastName } }
sumber
lazy var
properti runtime secara efektif untuk mengecualikannya dari Codable.Meskipun hal ini dapat dilakukan, pada akhirnya akan menjadi sangat tidak sopan dan bahkan tidak PRIBADI . Saya rasa saya melihat dari mana Anda berasal, konsep
#id
s lazim di HTML, tetapi jarang dibawa ke duniaJSON
yang saya anggap sebagai hal yang baik (TM).Beberapa
Codable
struct akan dapat menguraiJSON
file Anda dengan baik jika Anda merestrukturnya menggunakan hash rekursif, yaitu jika Andarecipe
hanya berisi sebuah arrayingredients
yang pada gilirannya berisi (satu atau beberapa)ingredient_info
. Dengan cara itu parser akan membantu Anda untuk menyatukan jaringan Anda dan Anda hanya perlu menyediakan beberapa tautan balik melalui struktur traversal sederhana jika Anda benar-benar membutuhkannya . Karena ini memerlukan pengerjaan ulang menyeluruh dari AndaJSON
dan struktur data Anda, saya hanya membuat sketsa ide agar Anda memikirkannya. Jika Anda menganggapnya dapat diterima, tolong beri tahu saya di komentar maka saya dapat menjelaskannya lebih lanjut, tetapi tergantung pada keadaan Anda mungkin tidak memiliki kebebasan untuk mengubah salah satu dari mereka.sumber
Saya telah menggunakan protokol dan ekstensinya bersama dengan AssociatedObject untuk mengatur dan mendapatkan properti gambar (atau properti apa pun yang perlu dikecualikan dari Codable).
Dengan ini kita tidak perlu mengimplementasikan Encoder dan Decoder kita sendiri
Ini kodenya, menyimpan kode yang relevan untuk kesederhanaan:
protocol SCAttachmentModelProtocol{ var image:UIImage? {get set} var anotherProperty:Int {get set} } extension SCAttachmentModelProtocol where Self: SCAttachmentUploadRequestModel{ var image:UIImage? { set{ //Use associated object property to set it } get{ //Use associated object property to get it } } } class SCAttachmentUploadRequestModel : SCAttachmentModelProtocol, Codable{ var anotherProperty:Int }
Sekarang, kapan pun kita ingin mengakses properti Image, kita dapat menggunakan objek yang mengonfirmasi protokol (SCAttachmentModelProtocol)
sumber