Почему определение CodingKeys для НЕКОТОРЫХ свойств требует инициализатора? - PullRequest
2 голосов
/ 21 февраля 2020

Хорошо компилируется без проблем:

class User: Codable {
    let name: String
    let email: String
}

Однако, если у нас есть свойство, не представленное CodingKey, оно требует инициализатора:

class User: Codable { // Class 'User' has no initializers
    let name: String
    let email: String

    private enum CodingKeys: String, CodingKey {
        case name = "username"
    }
}

Почему оно решает, что проблема заключается в отсутствии синтезированных инициализаторов, вместо предупреждения или ошибки, требующей CodingKey? Почему это нарушает соответствие Decodable?

Редактировать: Поскольку некоторые люди, кажется, смущены, я не спрашиваю, как устранить ошибку. Это очевидно. Я спрашиваю, что происходит в протоколе Codable, когда вы не указываете CodingKey для обязательного свойства.

Ответы [ 3 ]

1 голос
/ 21 февраля 2020

Класс с хотя бы одним свойством, которое не имеет значения по умолчанию, нуждается в инициализаторе для инициализации этого свойства.

class User {
    let name: String
    let email: String
}

Класс «Пользователь» не имеет инициализаторов

Когда вы соответствуете Codable или, более конкретно, Decodable, как вы хорошо заметили, класс получает синтезированный инициализатор, а именно User.init(from: Decoder), который устраняет вышеуказанную проблему. Этот синтезированный инициализатор будет использовать ключи кодирования, названные в соответствии со свойствами.

class User: Decodable { ... }

Как только вы определите перечисление в User, называемое CodingKeys (точное имя важно), синтез Decodable соответствие потребует наличия ключа для каждого свойства . Другими словами, как только один ключ отклоняется от имени свойства, вы должны определить ключ кодирования для каждого свойства.

Следующее делает это и компилирует:

class User: Decodable {
    let name: String
    let email: String

    private enum CodingKeys: String, CodingKey {
        case name = "username"
        case email
    }
}

Если нет указав ключ email, компилятор не будет знать, как установить это свойство, знает только как разработчик. Следовательно, компилятор не будет синтезировать его для вас, и вам придется.

Там может быть естественное значение по умолчанию, как показано здесь:

class User: Decodable {
    let name: String
    let email: String

    enum CodingKeys: String, CodingKey {
        case name = "username"
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        name = try container.decode(String.self, forKey: .name)

        // Default email:
        email = "\(name)@example.com"
    }
}
0 голосов
/ 21 февраля 2020

Даже если вам не понадобится CodingKey для email, вам все равно придется объявить его регистр без какого-либо значения, как в:

   private enum CodingKeys: String, CodingKey {
     case name = "username"
     case email
   }
0 голосов
/ 21 февраля 2020

Xcode выбрасывает первое в строке ошибок, вызванных вторым примером. Если вы добавите инициализатор, он, вероятно, затем расскажет вам о чем-то, что связано с отсутствием кодирующего ключа для свойства name. Однако, когда вы не определяете CodingKeys, он может создать для вас CodingKeys, а также инициализатор по умолчанию.

...