Стратегия convertFromSnakeCase не работает с пользовательскими ключами CodingKeys в Swift

Я пытаюсь использовать новую функцию Swift 4.1 для преобразования snake-case в camelCase во время декодирования JSON.

Вот пример :

struct StudentInfo: Decodable {
    internal let studentID: String
    internal let name: String
    internal let testScore: String

    private enum CodingKeys: String, CodingKey {
        case studentID = "student_id"
        case name
        case testScore
    }
}

let jsonString = """
{"student_id":"123","name":"Apple Bay Street","test_score":"94608"}
"""

do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let decoded = try decoder.decode(StudentInfo.self, from: Data(jsonString.utf8))
    print(decoded)
} catch {
    print(error)
}

Мне нужно предоставить настраиваемый CodingKeys, поскольку стратегия convertFromSnakeCase не может делать вывод о капитализации аббревиатур или инициализмов (например, studentID), но я ожидаю, что стратегия convertFromSnakeCase будет по-прежнему работать для testScore. Однако декодер выдает ошибку («Нет значения, связанного с ключом CodingKeys»), и мне кажется, что я не могу использовать convertFromSnakeCase стратегию и пользовательский CodingKeys одновременно. Я что-то упускаю?


person Howard    schedule 17.04.2018    source источник
comment
Вы хотите case studentID = "studentId" (сравните stackoverflow.com/a/44396824/2976878) - декодер применяет ключевую стратегию до обращения к кодированию ключи, поэтому он преобразует "student_id" в "studentId".   -  person Hamish    schedule 17.04.2018
comment
Спасибо, @Hamish! Это работает!   -  person Howard    schedule 17.04.2018
comment
@Rob Будет делать, когда у меня будет минутка (то есть, если за это время никто не отправит ответ)   -  person Hamish    schedule 17.04.2018


Ответы (1)


Ключевые стратегии для JSONDecoderJSONEncoder) применяются ко всем ключам в полезной нагрузке, включая те, для которых вы предоставляете настраиваемый ключ кодирования. При декодировании ключ JSON сначала будет сопоставлен с использованием заданной ключевой стратегии, а затем декодер обратится к CodingKeys для данного декодируемого типа.

В вашем случае ключ student_id в вашем JSON будет сопоставлен с studentId на .convertFromSnakeCase. Точный алгоритм преобразования приведен в документации:

  1. Каждое слово после подчеркивания пишите с заглавной буквы.

  2. Удалите все подчеркивания, которые не находятся в самом начале или конце строки.

  3. Объедините слова в одну строку.

Следующие примеры показывают результат применения этой стратегии:

fee_fi_fo_fum

Преобразуется в: feeFiFoFum

feeFiFoFum

Преобразуется в: feeFiFoFum

base_uri

Преобразуется в: baseUri

Поэтому вам необходимо обновить свой CodingKeys, чтобы он соответствовал этому:

internal struct StudentInfo: Decodable, Equatable {
  internal let studentID: String
  internal let name: String
  internal let testScore: String

  private enum CodingKeys: String, CodingKey {
    case studentID = "studentId"
    case name
    case testScore
  }
}
person Hamish    schedule 17.04.2018
comment
Вау! Большое спасибо, что указали ПОРЯДОК преобразований! - person Carsten; 04.05.2019
comment
Действительно полезный ответ, хотя в результате я не буду использовать keyDecodingStrategy, потому что это делает код значительно менее читаемым. - person alex bird; 24.01.2020
comment
Отличный ответ ???????? - person George Marmaridis; 08.04.2021