#ios #json #swift #decoding #codable
#iOS #json #swift #декодирование #кодируемый
Вопрос:
Может кто-нибудь, пожалуйста, объяснить, почему код в части A работает, а B не нравится. Это сбило меня с толку.
РАБОТАЕТ
struct Coded : Codable, Hashable {
public let avar1: String
public let avar2: String
enum CodingKeys: String, CodingKey {
case avar1 = "avar1"
case avar2 = "avar2"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
print (container.allKeys)
avar1 = try container.decode(String.self, forKey: .avar1)
avar2 = try container.decode(String.self, forKey: .avar2)
}
}
let JSONStr = """
{
"avar1": "This is a string",
"avar2": "This is a string2",
}
"""
if let jsdata = JSONStr.data(using: .utf8) {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let aobj: Coded? = try? decoder.decode(Coded.self, from: jsdata)
print (aobj ?? "No object")
}
ВЫВОД
[CodingKeys(stringValue: "avar1", intValue: nil), CodingKeys(stringValue: "avar2", intValue: nil)]
Coded(avar1: "This is a string", avar2: "This is a string2")
НЕ РАБОТАЕТ
struct Coded : Codable, Hashable {
public let avar1: String
public let avar2: String
enum CodingKeys: String, CodingKey {
case avar1 = "avar1"
case avar2 = "avar_2"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
print (container.allKeys)
avar1 = try container.decode(String.self, forKey: .avar1)
avar2 = try container.decode(String.self, forKey: .avar2)
}
}
let JSONStr = """
{
"avar1": "This is a string",
"avar_2": "This is a string2",
}
"""
if let jsdata = JSONStr.data(using: .utf8) {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let aobj: Coded? = try? decoder.decode(Coded.self, from: jsdata)
print (aobj ?? "No object")
}
ВЫВОД
[CodingKeys(stringValue: "avar1", intValue: nil)]
No object
Вторая функция будет отображать только ключ кодирования без подчеркивания. Но как только я удаляю подчеркивание, у него появляется ключ кодирования в allKeys…
Swift 4.2 — Xcode 10.2.
Есть идеи?
Комментарии:
1. Я, наконец, получил эту работу после закрытия моей игровой площадки и запуска ее снова. Похоже, это может быть проблема с интерпретатором… Это чрезвычайно странно.
2. Похоже, что большие наборы данных использовали .convertFromSnakeCase, что привело к исчезновению ключей кодирования во время декодирования.
Ответ №1:
.convertFromSnakeCase
преобразует переменные snake_cased в camelCase перед обращением к CodingKeys
.
Если вы хотите указать, CodingKeys
вы должны использовать преобразованное значение в вашем НЕ РАБОЧЕМ примере
enum CodingKeys: String, CodingKey {
case avar1 = "avar1"
case avar2 = "avar2"
}
Но это иллюстрирует бессмысленность CodingKeys
. Поэтому подумайте наоборот и воспользуйтесь стратегией декодирования ключей.
Вместо удаления .convertFromSnakeCase
удалите CodingKeys
и инициализатор.
И всегда ловите возможные Decoding
ошибки.
struct Coded : Codable {
public let avar1: String
public let avar2: String
}
let jsonStr = """
{
"avar1": "This is a string",
"avar_2": "This is a string2",
}
"""
let jsdata = Data(jsonStr.utf8)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let aobj = try decoder.decode(Coded.self, from: jsdata)
print(aobj)
} catch { print(error) }
Комментарии:
1. Спасибо, что поделились информацией о том, что ключи преобразуются в верблюжий регистр перед доступом к ключам кодирования. Мое личное предпочтение было бы удалить convertFromSnakeCase, потому что его использование запутало привязку ключей к именам переменных в JSON.
Ответ №2:
Я исправил эту проблему. Это связано с проблемой, возникающей при использовании Snake Case. В некоторых ситуациях это может вызвать проблемы. Что это такое и почему они происходят, я не уверен. Но если у вас есть JSONDecoder с включенным запуском Snake Case. Это удалит коды клавиш для элементов, которые закодированы с использованием регистра snake.
Удалив следующее из моего JSONDecoder, я смог устранить проблему.
Пожалуйста, удалите следующее и принудительно введите строки кодирования в регистр snake, если у вас установлен этот параметр, и принудительно используйте стратегию JSONDecoder с помощью .convertFromSnakeCase, это удалит строки ключей кодирования и сломается во время декодирования.
Если ваши ключи кодирования включают
codingKey = "a_json_var"
Если вы добавите convertFromSnakeCase , это полностью удалит ключ кодирования. Итак, не указывайте текстовую строку в регистре ключа кодирования в регистре snake, иначе она сломается.
Удалить ->
decoder.keyDecodingStrategy = .convertFromSnakeCase
Если вы хотите правильно указать точное текстовое название ключа кодирования.