#ios #swift #codable #decodable #encodable
#iOS #swift #кодируемый #декодируемый
Вопрос:
Я хочу отправить пустой словарь следующим образом
“visitor_attrs”: {}
Я пытаюсь реализовать пустой словарь в классе. В декодере я получаю предупреждение:
Ни один из кандидатов ‘decode’ не выдает ожидаемый контекстный результат типа ‘Dictionary’
Как я могу это сделать?
var data: String
var event: String
var visitorAttrs: Dictionary<String, Any>
init(data: String, event: String) {
self.data = data
self.event = event
self.visitorAttrs = [:]
}
private enum CodingKeys: String, CodingKey {
case data
case event
case visitorAttrs = "visitor_attrs"
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.data = try container.decode(String.self, forKey: .data)
self.event = try container.decode(String.self, forKey: .event)
self.visitorAttrs = try container.decode(Dictionary<String:Any>.self, forKey: .visitorAttrs)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.data, forKey: .data)
try container.encode(self.event, forKey: .event)
try container.encode(self.visitorAttrs, forKey: .visitorAttrs)
}
Ответ №1:
Я предполагаю, что, поскольку visitorAttrs пуст в вашем ответе JSON, из него не удается извлечь словарь, поскольку его нет.
У вас есть два варианта (насколько я знаю)
-
Сделайте свойство visitorAttrs необязательным, таким образом, если у вас ничего нет, оно все равно сможет правильно декодироваться, или,
-
Установите значение visitorAttrs в пустой словарь, если не удается его декодировать
let visitorAttrs = try? container.decode(Dictionary<String:Any>.self, forKey: .visitorAttrs)
self.visitorAttrs = visitorAttrs ?? [:]
Ответ №2:
Ошибка вызвана наличием любого значения as в вашем словаре, и любое из них не поддается декодированию, замените его на String (или любой другой тип данных, который у вас есть), и это должно сработать.
var visitorAttrs: Dictionary<String, String>
Исправьте эту проблему, и вы получите ожидаемое поведение
let item = Item(data: "data", event: "event") //I gave your class the name Item
let encoder = JSONEncoder()
do {
let data = try encoder.encode(item)
if let str = String(data: data, encoding: .utf8) {
print(str)
}
} catch {
print(error)
}
Вывод
{«event»: «событие», «visitor_attrs»:{},»data»: «данные»}
Комментарии:
1. Другим вариантом было бы использовать здесь пустой
Codable
тип. Нравитсяstruct Stub: Codable {}
. Это тоже будет работать, и не нужно предоставлять нерелевантную информацию о типе, такую как<String, String>
.2. @user28434 Да, но нет, если он иногда будет содержать данные, полный вариант использования неясен.
3. Действительно, но если он содержит данные, все равно может быть лучше использовать
Codable
class , только со всеми полями, равнымиOptional
. Я сомневаюсь, что все значения будут одного типа.