Новые протоколы Encodable
/ Swift 4 Decodable
делают (де) сериализацию JSON довольно приятной. Однако я еще не нашел способа детального контроля над тем, какие свойства следует кодировать, а какие декодировать.
Я заметил, что исключение свойства из сопутствующего CodingKeys
перечисления полностью исключает свойство из процесса, но есть ли способ получить более детальный контроль?
CodingKeys
перечисления.Codable
протокола (init(from:)
иencode(to:)
) вручную для полного контроля над процессом.Ответы:
Список ключей для кодирования / декодирования контролируется вызываемым типом
CodingKeys
(обратите внимание наs
значок в конце). Компилятор может синтезировать это за вас, но всегда может это отменить.Допустим, вы хотите исключить свойство
nickname
как из кодирования, так и из декодирования:struct Person: Codable { var firstName: String var lastName: String var nickname: String? private enum CodingKeys: String, CodingKey { case firstName, lastName } }
Если вы хотите, чтобы он был асимметричным (т.е. кодировал, но не декодировал, или наоборот), вы должны предоставить свои собственные реализации
encode(with encoder: )
иinit(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) } }
источник
nickname
указать значение по умолчанию, чтобы это работало. В противном случае свойству не может быть присвоено какое-либо значениеinit(from:)
.encode
в асимметричном примере? Поскольку это все еще стандартное поведение, я не думал, что это нужно. Простоdecode
потому, что отсюда и происходит асимметрия.fullName
не может быть сопоставлено с сохраненным свойством, вы должны предоставить настраиваемый кодировщик и декодер.Если нам нужно исключить декодирование пары свойств из большого набора свойств в структуре, объявите их как необязательные свойства. Код для развертывания опций меньше, чем запись большого количества ключей в перечислении CodingKey.
Я бы рекомендовал использовать расширения для добавления свойств вычисляемого экземпляра и свойств вычисляемого типа. Он отделяет кодируемые свойства от другой логики, поэтому обеспечивает лучшую читаемость.
источник
Другой способ исключить некоторые свойства из кодировщика, можно использовать отдельный контейнер кодирования
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"} }
тот же подход можно использовать для декодера
источник
Вы можете использовать вычисленные свойства:
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 } }
источник
lazy var
эффективного свойства времени выполнения исключило его из Codable.Хотя это можно сделать, в конечном итоге это оказывается очень непостоянным и даже не JSONy . Думаю, я понимаю, откуда вы пришли, концепция
#id
s преобладает в HTML, но она редко переносится в мир,JSON
который я считаю хорошим (TM).Некоторые
Codable
структуры смогутJSON
нормально анализировать ваш файл, если вы реструктурируете его с помощью рекурсивных хэшей, т.е. если вашrecipe
просто содержит массив,ingredients
который, в свою очередь, содержит (один или несколько)ingredient_info
. Таким образом, синтаксический анализатор поможет вам в первую очередь объединить вашу сеть, и вам нужно будет только предоставить некоторые обратные ссылки через простой обход структуры, если они вам действительно нужны . Поскольку для этого требуется тщательная переработка вашейJSON
и вашей структуры данных, я лишь набросаю вам идею, чтобы вы ее обдумали. Если вы считаете это приемлемым, сообщите мне в комментариях, и я мог бы уточнить это подробнее, но в зависимости от обстоятельств вы не вправе изменять любой из них.источник
Я использовал протокол и его расширение вместе с AssociatedObject для установки и получения свойства изображения (или любого свойства, которое необходимо исключить из Codable).
При этом нам не нужно реализовывать собственный кодировщик и декодер.
Вот код, для простоты сохраняющий соответствующий код:
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 }
Теперь, когда мы хотим получить доступ к свойству Image, мы можем использовать объект, подтверждающий протокол (SCAttachmentModelProtocol)
источник