Protokół Codable został wprowadzony w Swift w celu uproszczenia procesu serializacji i deserializacji danych, takich jak JSON czy Property List. Wcześniej wymagało to ręcznej realizacji parsowania, co było pracochłonne, podatne na błędy i mało czytelne. Automatyzacja tego procesu pozwoliła na tworzenie bardziej bezpiecznego i zwięzłego kodu.
Problem polega na tym, że przy automatycznym zastosowaniu Codable wszystkie właściwości muszą być również Codable, a każde naruszenie tego łańcucha wymaga wyraźnej implementacji metod dekodowania i kodowania. Oprócz tego istnieją szczególne kwestie przy pracy z strukturami, klasami z dziedziczeniem, a także przy dostosowywaniu mapowania kluczy.
Rozwiązanie polega na używaniu Codable dla prostych modeli, uważnym śledzeniu, które właściwości powinny być serializowane oraz w przypadku złożonych modeli implementacji metod encode(to:) i init(from:), a także używania CodingKeys do mapowania kluczy.
Przykład kodu:
struct User: Codable { let id: Int let name: String let email: String? enum CodingKeys: String, CodingKey { case id case name = "full_name" case email = "contact_email" } }
Kluczowe cechy:
Czy klasa z dziedziczeniem i unikalnymi właściwościami potomka może być automatycznie poprawnie serializowana przy użyciu Codable?
Nie, dla klas z dziedziczeniem Swift wymaga ręcznej implementacji encode(to:) i init(from:) w podklasach, w przeciwnym razie właściwości rodzica i potomka nie są poprawnie serializowane. Przykład:
class Animal: Codable { let species: String } class Dog: Animal { let breed: String enum CodingKeys: String, CodingKey { case breed } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) breed = try container.decode(String.self, forKey: .breed) try super.init(from: decoder) } override func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(breed, forKey: .breed) try super.encode(to: encoder) } }
Co się stanie, jeśli właściwość w strukturze jest oznaczona jako private, a używana jest automatyczna Codable?
Jeśli właściwość jest prywatna i nie została zadeklarowana jako var/let z wyraźnym CodingKeys, nie zostanie serializowana ani deserializowana. Dlatego dla prywatnych właściwości należy koniecznie deklarować CodingKeys i uwzględnić je w enumeracji w razie potrzeby.
Czy możliwe jest zaimplementowanie Codable tylko dla dekodowania (tylko do odczytu)?
Tak, wystarczy zaimplementować tylko init(from:) i przestrzegać protokołu Decodable zamiast Codable.
struct ReadOnlyModel: Decodable { let id: Int }
** Negatywny przypadek
Programista dodał do modelu właściwość obliczaną, nie wdrażając niestandardowych metod encode i decode, licząc na automatyczne przetwarzanie Codable.
Zalety:
Wady:
** Pozytywny przypadek
Programista implementuje niestandardowe CodingKeys i niestandardowe metody encode/decode dla złożonych przypadków, gdzie właściwości nie odpowiadają kluczom, są pola obliczane i stosuje się dziedziczenie.
Zalety:
Wady: