Кодируемая переменная внутри кодируемой структуры вызывает ошибку

Пожалуйста, взгляните на мой код:

Нет ошибок

struct Person: Codable {
    var name: String
    var age: Double
    var birthday: Date
    
    var selectedItem: Car
}

struct Car: Codable {
    var companyName: String
    var creationDate: Date
}

struct iPhone: Codable {
    var model: String
    var creationDate: Date
    var isScreenBroken: Bool = true
}

Ошибка сборки

struct Person: Codable { // "Type 'Person' does not conform to protocol 'Decodable'", "Type 'Person' does not conform to protocol 'Encodable'"
    var name: String
    var age: Double
    var birthday: Date
    
    var selectedItem: Codable // I've changed this line
}

struct Car: Codable {
    var companyName: String
    var creationDate: Date
}

struct iPhone: Codable {
    var model: String
    var creationDate: Date
    var isScreenBroken: Bool = true
}

Тип «Человек» не соответствует протоколу «Декодируемый»

Тип «Человек» не соответствует протоколу «Кодируемый»

Я не понимаю, почему это происходит. Он знает, что selectedItem соответствует Encodable и Decodable:

var selectedItem: Codable

Я новичок в протоколах в Swift, поэтому, отвечая, постарайтесь объяснить, что здесь происходит.

Спасибо!


person אורי orihpt    schedule 01.01.2021    source источник
comment
как он узнает, что selectedItem соответствует Codable? Очевидно, что выбранный элемент больше не относится к типу автомобиля.   -  person zeytin    schedule 01.01.2021
comment
@зейтин var selectedItem: Codable   -  person אורי orihpt    schedule 01.01.2021
comment
Он должен был бы декодировать selectedItem в определенный тип, который не объявлен. Простое заявление о том, что оно соответствует Codable, не поможет в декодировании, если оно не имеет типа.   -  person Chris    schedule 01.01.2021
comment
Вы можете создать новый тип для selectedItem, который соответствует Codable, или установить его на конкретный тип, такой как Int или String.   -  person Chris    schedule 01.01.2021
comment
Не могли бы вы дать ответ и привести пример? @Крис   -  person אורי orihpt    schedule 01.01.2021


Ответы (1)


Проблема для компилятора здесь заключается в том, что обычно, когда тип определяется как соответствующий Codable, компилятор синтезирует код для вас, чтобы в этом случае Person соответствовал протоколу. Он делает это, создавая для вас реализацию init(from decoder: Decoder) throws и одну из func encode(to encoder: Encoder) throws.

Но когда вы меняете selectedItem на тип Codable, компилятор больше не может синтезировать эти методы, поскольку ему необходимо точно знать, какими свойствами должен обладать тип selectedItem, чтобы правильно генерировать код.

Здесь вам нужно использовать универсальные шаблоны.

struct Person<T: Codable>: Codable {
    var name: String
    var age: Double
    var birthday: Date

    var selectedItem: T
}

struct Car: Codable {
    var companyName: String
    var creationDate: Date
}

struct iPhone: Codable {
    var model: String
    var creationDate: Date
    var isScreenBroken: Bool = true
}

Тогда компилятор снова счастлив, и вы можете использовать его как

let person = Person(name: "Joe", age: 40, birthday: date, selectedItem: Car(companyName: "Ford", creationDate: Date()))
person Joakim Danielson    schedule 01.01.2021