Berikut adalah implementasi sederhana dari DictionaryEncoder/ DictionaryDecoderthat wrap JSONEncoder, JSONDecoderdan JSONSerialization, yang juga menangani strategi encoding / decoding…
Terima kasih banyak!, Alternatifnya adalah menggunakan pewarisan tetapi situs pemanggil tidak dapat menyimpulkan jenisnya sebagai kamus karena akan ada 2 fungsi dari jenis pengembalian yang berbeda.
pengguna1046037
17
Saya telah membuat pustaka bernama CodableFirebase dan tujuan awalnya adalah menggunakannya dengan Firebase Database, tetapi sebenarnya ini melakukan apa yang Anda butuhkan: membuat kamus atau jenis lain seperti di JSONDecodertetapi Anda tidak perlu melakukan konversi ganda di sini seperti yang Anda lakukan di jawaban lain. Jadi akan terlihat seperti ini:
importCodableFirebaselet model =Foo(a:1, b:2)let dict =try!FirebaseEncoder().encode(model)
Ini hanya akan bekerja untuk struktur dengan semua properti dari jenis yang sama
Leo Dabus
1
Saya baru saja mencoba "let dict = try JSONDecoder (). Decode ([String: Int] .self, from: JSONEncoder (). Encode (foo))" dan saya mendapat "Diharapkan untuk memecahkan kode Dictionary <String, Any> tetapi menemukan array sebagai gantinya. " bisakah kamu membantu
Tidak ada cara bawaan untuk melakukan itu. Seperti yang dijawab di atas, jika Anda tidak memiliki masalah kinerja, maka Anda dapat menerima JSONEncoder+ JSONSerializationimplementasi.
Tapi saya lebih suka menggunakan cara perpustakaan standar untuk menyediakan objek encoder / decoder.
classDictionaryEncoder{privatelet jsonEncoder =JSONEncoder()/// Encodes given Encodable value into an array or dictionary
func encode<T>(_ value: T)throws->Anywhere T:Encodable{let jsonData =try jsonEncoder.encode(value)returntryJSONSerialization.jsonObject(with: jsonData, options:.allowFragments)}}classDictionaryDecoder{privatelet jsonDecoder =JSONDecoder()/// Decodes given Decodable type from given array or dictionary
func decode<T>(_ type: T.Type, from json:Any)throws-> T where T:Decodable{let jsonData =tryJSONSerialization.data(withJSONObject: json, options:[])returntry jsonDecoder.decode(type, from: jsonData)}}
Saya benar-benar berpikir bahwa ada beberapa nilai dalam hanya dapat digunakan Codableuntuk menyandikan ke / dari kamus, tanpa niat untuk memukul JSON / Plists / apa pun. Ada banyak API yang hanya mengembalikan kamus, atau mengharapkan kamus, dan senang dapat menukarnya dengan mudah dengan struct atau objek Swift, tanpa harus menulis kode boilerplate tanpa akhir.
Saya telah bermain-main dengan beberapa kode berdasarkan sumber Foundation JSONEncoder.swift (yang sebenarnya mengimplementasikan encoding / decoding kamus secara internal, tetapi tidak mengekspornya).
Saya telah memodifikasi PropertyListEncoder dari proyek Swift menjadi DictionaryEncoder, cukup dengan menghapus serialisasi terakhir dari kamus ke dalam format biner. Anda dapat melakukan hal yang sama sendiri, atau Anda dapat mengambil kode saya dari sini
Saya menulis inti singkat untuk menangani ini (tidak menggunakan protokol Codable). Hati-hati, ini tidak memeriksa ketikan nilai apa pun dan tidak berfungsi secara rekursif pada nilai yang dapat dienkode.
classDictionaryEncoder{var result:[String:Any]init(){
result =[:]}func encode(_ encodable:DictionaryEncodable)->[String:Any]{
encodable.encode(self)return result
}func encode<T, K>(_ value: T, key: K)where K:RawRepresentable, K.RawValue==String{
result[key.rawValue]= value
}}protocolDictionaryEncodable{func encode(_ encoder:DictionaryEncoder)}
Tidak ada cara langsung untuk melakukan ini di Codable. Anda perlu menerapkan protokol Encodable / Decodable untuk struct Anda. Untuk contoh Anda, Anda mungkin perlu menulis seperti di bawah ini
Kalau dipikir-pikir, pertanyaannya tidak memiliki jawaban dalam kasus umum, karena Encodableinstance tersebut mungkin sesuatu yang tidak dapat diserialkan ke dalam kamus, seperti array:
let payload =[1,2,3]let encoded =tryJSONEncoder().encode(payload)//"[1,2,3]"
Saya harus mengakui bahwa saya masih tidak mengerti mengapa ini diturunkan suara :–) Apakah peringatan tersebut tidak benar? Atau kerangka tidak berguna?
Jawaban:
Jika Anda tidak keberatan dengan sedikit pergeseran data di sekitar Anda, Anda dapat menggunakan sesuatu seperti ini:
Atau varian opsional
Dengan asumsi
Foo
sesuai denganCodable
atau benar-benarEncodable
maka Anda dapat melakukan ini.Jika Anda ingin pergi ke arah lain (
init(any)
), lihat objek Init ini yang sesuai dengan Codable dengan kamus / lariksumber
Berikut adalah implementasi sederhana dari
DictionaryEncoder
/DictionaryDecoder
that wrapJSONEncoder
,JSONDecoder
danJSONSerialization
, yang juga menangani strategi encoding / decoding…Penggunaannya mirip dengan
JSONEncoder
/JSONDecoder
…dan
Untuk kenyamanan, saya telah menempatkan ini semua dalam repo… https://github.com/ashleymills/SwiftDictionaryCoding
sumber
Saya telah membuat pustaka bernama CodableFirebase dan tujuan awalnya adalah menggunakannya dengan Firebase Database, tetapi sebenarnya ini melakukan apa yang Anda butuhkan: membuat kamus atau jenis lain seperti di
JSONDecoder
tetapi Anda tidak perlu melakukan konversi ganda di sini seperti yang Anda lakukan di jawaban lain. Jadi akan terlihat seperti ini:sumber
Saya tidak yakin apakah itu cara terbaik tetapi Anda pasti dapat melakukan sesuatu seperti:
sumber
let dict = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(struct), options: []) as? [String: Any]
sumber
Tidak ada cara bawaan untuk melakukan itu. Seperti yang dijawab di atas, jika Anda tidak memiliki masalah kinerja, maka Anda dapat menerima
JSONEncoder
+JSONSerialization
implementasi.Tapi saya lebih suka menggunakan cara perpustakaan standar untuk menyediakan objek encoder / decoder.
Anda dapat mencobanya dengan kode berikut:
Di sini saya mencoba paksa untuk mempersingkat contoh. Dalam kode produksi, Anda harus menangani kesalahan dengan tepat.
sumber
Dalam beberapa proyek, saya menggunakan refleksi cepat. Tapi hati-hati, objek codable bersarang, jangan dipetakan juga di sana.
sumber
Saya benar-benar berpikir bahwa ada beberapa nilai dalam hanya dapat digunakan
Codable
untuk menyandikan ke / dari kamus, tanpa niat untuk memukul JSON / Plists / apa pun. Ada banyak API yang hanya mengembalikan kamus, atau mengharapkan kamus, dan senang dapat menukarnya dengan mudah dengan struct atau objek Swift, tanpa harus menulis kode boilerplate tanpa akhir.Saya telah bermain-main dengan beberapa kode berdasarkan sumber Foundation JSONEncoder.swift (yang sebenarnya mengimplementasikan encoding / decoding kamus secara internal, tetapi tidak mengekspornya).
Kode tersebut dapat ditemukan di sini: https://github.com/elegantchaos/DictionaryCoding
Ini masih cukup kasar, tetapi saya telah mengembangkannya sedikit sehingga, misalnya, dapat mengisi nilai yang hilang dengan default saat mendekode.
sumber
Saya telah memodifikasi PropertyListEncoder dari proyek Swift menjadi DictionaryEncoder, cukup dengan menghapus serialisasi terakhir dari kamus ke dalam format biner. Anda dapat melakukan hal yang sama sendiri, atau Anda dapat mengambil kode saya dari sini
Ini bisa digunakan seperti ini:
sumber
Saya menulis inti singkat untuk menangani ini (tidak menggunakan protokol Codable). Hati-hati, ini tidak memeriksa ketikan nilai apa pun dan tidak berfungsi secara rekursif pada nilai yang dapat dienkode.
sumber
Tidak ada cara langsung untuk melakukan ini di Codable. Anda perlu menerapkan protokol Encodable / Decodable untuk struct Anda. Untuk contoh Anda, Anda mungkin perlu menulis seperti di bawah ini
sumber
Saya telah membuat pod di sini https://github.com/levantAJ/AnyCodable untuk memfasilitasi decode dan encode
[String: Any]
dan[Any]
Dan Anda dapat memecahkan kode & menyandikan
[String: Any]
dan[Any]
sumber
Jika Anda menggunakan SwiftyJSON , Anda dapat melakukan sesuatu seperti ini:
JSON(data: JSONEncoder().encode(foo)).dictionaryObject
sumber
Berikut adalah solusi berbasis protokol:
Dan inilah cara menggunakannya:
sumber
Ini kamus -> objek. Cepat 5.
sumber
Kalau dipikir-pikir, pertanyaannya tidak memiliki jawaban dalam kasus umum, karena
Encodable
instance tersebut mungkin sesuatu yang tidak dapat diserialkan ke dalam kamus, seperti array:Selain itu, saya telah menulis sesuatu yang mirip sebagai kerangka kerja .
sumber