Словарь декодирования Swift JSON не работает

У меня есть структура, показанная ниже:

struct ItemList: Decodable {
    var items: [UUID: Int]
}

Я получаю следующие данные JSON:

{
    "items": {
        "b4f8d2fa-941f-4f9a-a98c-060bbd468575": 418226428193,
        "81efa661-4845-491b-8bf4-06d5dff1d5f8": 417639857722
    }
}

Теперь, когда я пытаюсь расшифровать приведенные выше данные, я получаю интересную ошибку. Ясно, что я не декодирую массив, и ясно, что все указывает на словарь.

try JSONDecoder().decode(ItemList.self, from: data)
// typeMismatch(
//     Swift.Array<Any>,
//     Swift.DecodingError.Context(
//         codingPath: [
//             CodingKeys(stringValue: "items", intValue: nil)
//         ],
//         debugDescription: "Expected to decode Array<Any> but found a dictionary instead.",
//         underlyingError: nil
//     )
// )

Итак, я пошел поэкспериментировать и изменил [UUID: Int] на [String: Int], что делает эту работу, почти заставляя меня думать, что ошибка связана не с массивом / словарем, а с UUID / String. Итак, я также провел следующий тест, который никогда не терпит неудач.

let list = try JSONDecoder().decode(ItemList.self, from: data)
for (key, value) in list.items {
    // This will never print `nil`
    print(UUID(uuidString: key))
}

Итак, у меня вопрос: почему я получаю эту странную ошибку typeMismatch при декодировании и почему она работает, когда я меняю UUID на String, поскольку она явно может быть правильно декодирована?


person Bram    schedule 14.04.2021    source источник
comment
Похоже, это неразрешенная ошибка, и можно возразить о ценности использования созданных извне значений uuid. Гарантированно ли они уникальны на вашем устройстве, я не уверен в этом   -  person Joakim Danielson    schedule 14.04.2021
comment
Кажется связанным: swiftsenpai.com/swift/decode-dynamic-keys-json   -  person Tomalak    schedule 14.04.2021
comment
На мой взгляд, это не ошибка. Тот факт, что ключ в словаре Decodable, не имеет большого значения, потому что JSON поддерживает только String как ключ словаря. Однако Decodable не может обеспечить, чтобы тип ключа мог декодировать String. Поэтому у них был выбор - попытаться декодировать String в данный тип и выбросить исключение, если это невозможно, или использовать другой способ хранения данных при обнаружении ключа, отличного от String. Первый вариант был бы проблематичным при кодировании, поэтому они выбрали второй.   -  person Sulthan    schedule 14.04.2021


Ответы (1)


эта статья дает хорошее объяснение того, почему это происходит и что вы можете сделать. об этом. Краткое содержание:

  • Swift кодирует словарь как массив, где каждое значение следует за ключом
  • Есть несколько подходов, которые можно использовать для решения проблемы:

a) Сделайте быстрый переход, используя представление dict в виде массива
b) Используйте String или Int в качестве ключевого типа
c) Используйте собственный декодер
d) Используйте RawRepresentable-Protocol

person Schottky    schedule 14.04.2021